[英]How to return serialized JSON from Flask-SQLAlchemy relationship query?
i'm using Flask-SQLAlchemy and i have the following models with one to many relationship,我正在使用 Flask-SQLAlchemy 并且我有以下具有一对多关系的模型,
class User(db.Model):
# Table name
__tablename__ = "users"
# Primary key
user_id = db.Column(db.Integer, primary_key=True)
# Fields (A-Z)
email = db.Column(db.String(50), nullable=False, unique=True)
password = db.Column(db.String, nullable=False)
username = db.Column(db.String(50), unique=True)
# Relationships (A-Z)
uploads = db.relationship("Upload", backref="user")
class Upload(db.Model):
# Table name
__tablename__ = "uploads"
# Primary key
upload_id = db.Column(db.Integer, primary_key=True)
# Fields (A-Z)
name = db.Column(db.String(50), nullable=False)
path_to_file = db.Column(db.String(256), nullable=False, unique=True)
uploaded_by = db.Column(db.Integer, db.ForeignKey("users.user_id"))
and i want to return JSON like this:我想像这样返回 JSON:
{
"users": [
{
"email": "vargovcik.marek@gmail.com",
"uploads": [
{
"name": "1.png",
"path_to_file": "static/1.png"
}
],
"username": "maro"
},
{
"email": "makos@gmail.com",
"uploads": [
{
"name": "2.jpg",
"path_to_file": "static/2.jpg"
}
],
"username": "makos"
}
]
}
So basically i want to return user object with all uploads (files user uploaded) in array.所以基本上我想返回用户 object 以及数组中的所有上传(用户上传的文件)。
I know i can access Upload class object within user with User.uploads (created with db.relationship) but i need some kind of serializer.我知道我可以使用 User.uploads(使用 db.relationship 创建)在用户中访问 Upload class object,但我需要某种序列化程序。
I wanted to add custom serialize() method to all my models:我想为我的所有模型添加自定义 serialize() 方法:
# User serializer
def serialize_user(self):
if self.uploads:
uploads = [upload.serialize_upload() for upload in self.uploads]
return {
"email": self.email,
"password": self.password,
"username": self.username,
"uploads": uploads
}
# Upload serializer
def serialize_upload(self):
if self.user:
dict_user = self.user.serialize_user()
return {
"name": self.name,
"path_to_file": self.path_to_file,
"user": dict_user
}
But problem with this is that i end up with nesting loop.但问题是我最终得到了嵌套循环。 My User object has upload files and each upload has it's user's data and these user's data has uploads files...
我的用户 object 有上传文件,每次上传都有它的用户数据,这些用户数据有上传文件......
My view endpoint:我的视图端点:
@app.route('/users', methods=["GET"])
def get_users():
users = [user.serialize_user() for user in User.query.all()]
return jsonify(users)
Error:错误:
RecursionError: maximum recursion depth exceeded while calling a Python object
Partial solution:部分解决方案:
I can simply ommit serializing user object inside Upload serializer but then i won't be able to create similiar endpoint but to get uploads.我可以简单地忽略在上传序列化程序中序列化用户 object,但是我将无法创建类似的端点,只能获取上传。 Example: /uploads - JSON with all uploads and user object nested.
示例:/uploads - JSON 嵌套了所有上传和用户 object。
How can i effectively work with relationships to return them as serialized JSON data similiar to JSON structure above?我如何有效地处理关系以将它们返回为类似于上面的 JSON 结构的序列化 JSON 数据?
As you said, you can simply write a second serializer
method. 如您所说,您可以简单地编写第二个
serializer
方法。 So you keep the other one for your /uploads API call. 因此,您可以保留另一个用于/ uploads API调用。
# User serializer
def serialize_user(self):
if self.uploads:
uploads = [upload.serialize_upload_bis() for upload in self.uploads]
return {
"email": self.email,
"password": self.password,
"username": self.username,
"uploads": uploads
}
# Upload serializer
def serialize_upload_bis(self):
return {
"name": self.name,
"path_to_file": self.path_to_file,
}
def serialize_upload(self):
if self.user:
dict_user = self.user.serialize_user()
return {
"name": self.name,
"path_to_file": self.path_to_file,
"user": dict_user
}
Although the question is quite old, I want to add a more generic answer, because I also was faced with this issue.虽然这个问题很老,但我想添加一个更通用的答案,因为我也遇到过这个问题。 The following serializer works for all classes with relationships:
以下序列化程序适用于所有具有关系的类:
from sqlalchemy.orm.collections import InstrumentedList
class Serializer(object):
def serialize(self):
serializedObject= {}
for c in inspect(self).attrs.keys():
attribute = getattr(self, c)
if(type(attribute) is InstrumentedList ):
serializedObject[c]= Component.serialize_list(attribute)
else:
serializedObject[c]= attribute
return serializedObject
@staticmethod
def serialize_list(l):
return [m.serialize() for m in l]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.