【问题标题】:How to return serialized JSON from Flask-SQLAlchemy relationship query?如何从 Flask-SQLAlchemy 关系查询中返回序列化的 JSON?
【发布时间】:2018-08-28 13:41:54
【问题描述】:

我正在使用 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"))

我想像这样返回 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"
        }
    ]
}

所以基本上我想用数组中的所有上传(用户上传的文件)返回用户对象。

我知道我可以使用 User.uploads(使用 db.relationship 创建)访问用户内的 Upload 类对象,但我需要某种序列化程序。

我想为我的所有模型添加自定义 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
        }

但问题是我最终会出现嵌套循环。我的用户对象有上传文件,每次上传都有它的用户数据,这些用户的数据有上传文件......

我的视图端点:

@app.route('/users', methods=["GET"])
def get_users():
    users = [user.serialize_user() for user in User.query.all()]
    return jsonify(users)

错误:

RecursionError: maximum recursion depth exceeded while calling a Python object

部分解决方案:

我可以简单地在 Upload 序列化程序中省略序列化用户对象,但是我将无法创建类似的端点,只能获取上传。 示例:/uploads - 包含所有上传和嵌套用户对象的 JSON。

我如何有效地处理关系以将它们作为类似于上述 JSON 结构的序列化 JSON 数据返回?

【问题讨论】:

    标签: python json sqlalchemy flask-sqlalchemy


    【解决方案1】:

    如您所说,您可以简单地编写第二个serializer 方法。因此,您保留另一个用于 /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
        }
    

    【讨论】:

    • 很久很久之后我又开始使用SO账号了。很抱歉不接受您的回答。我最终使用了名为 Marshmallow 的 Python 库,它负责模式转储/加载,但您的答案也是正确的,但需要更多工作。祝您有美好的一天。
    • 谢谢!不知道这个库,去看看吧!也祝你有美好的一天;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 2012-09-17
    • 2015-03-10
    • 1970-01-01
    相关资源
    最近更新 更多