You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flask API返回关联Outlet数据时抛出TypeError: Object of type Outlet is not JSON serializable问题求助

嘿,这个问题我之前也踩过同款坑!核心原因很简单:jsonify只能处理Python原生的数据类型(比如字典、列表、字符串、数字这些),但你返回的contact.outlets是一堆SQLAlchemy的Outlet模型实例,直接丢给jsonify它根本不知道怎么转成JSON,所以就抛出了那个序列化错误。

下面给你两种可行的解决方案,从简单手动处理到更规范的工具化实现都有:

方案1:改造现有to_json方法,手动序列化关联数据

你已经在Outlet模型里写了to_json方法,但里面的"contacts": self.contacts会触发同样的序列化问题(因为contactsContact实例),还会引发循环引用(Contact和Outlet互相引用)。先调整这个方法:

class Outlet(db.Model):
    # 其他代码保持不变
    def to_json(self):
        return {
            "id": self.id,
            "name": self.name,
            "website": self.website,
            "description": self.description,
            "image_url": self.image_url,
            # 只返回关联联系人的ID列表,避免循环和序列化问题
            "contact_ids": [contact.id for contact in self.contacts]
        }

然后修改你的路由,把contact.outlets转换成序列化后的列表,同时注意datetime对象也要转成字符串:

@contacts.get("/<int:id>")
@jwt_required()
def get_contact(id):
    contact = Contact.query.filter_by(id=id).first()
    if not contact:
        return jsonify({'message':'Item not found'}), HTTP_404_NOT_FOUND
    return jsonify({
        'id':contact.id,
        'name':contact.name,
        'email':contact.email,
        'bio':contact.bio,
        'image_url':contact.image_url,
        # 手动遍历每个Outlet,调用to_json转成可序列化的字典
        'outlets': [outlet.to_json() for outlet in contact.outlets],
        # datetime对象要转成ISO格式字符串
        'created_at':contact.created_at.isoformat(),
        'updated_at':contact.updated_at.isoformat() if contact.updated_at else None,
    }), HTTP_200_OK

方案2:用Marshmallow实现规范的序列化(更推荐)

如果你的API需要频繁处理模型序列化,Marshmallow是更专业的选择,它能自动处理关联关系、字段转换和循环引用问题。

  1. 先安装依赖:
pip install marshmallow-sqlalchemy
  1. 定义序列化Schema:
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from marshmallow import fields

class OutletSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Outlet
        include_fk = True  # 包含外键字段
        load_instance = True

    # 只返回联系人ID列表,避免循环引用
    contacts = fields.List(fields.Integer())

class ContactSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Contact
        include_fk = True
        load_instance = True

    # 用OutletSchema序列化关联的Outlet列表
    outlets = fields.List(fields.Nested(OutletSchema))
    # 自动把datetime转成ISO格式字符串
    created_at = fields.DateTime(format='iso')
    updated_at = fields.DateTime(format='iso', allow_none=True)
  1. 在路由里使用Schema:
@contacts.get("/<int:id>")
@jwt_required()
def get_contact(id):
    contact = Contact.query.filter_by(id=id).first()
    if not contact:
        return jsonify({'message':'Item not found'}), HTTP_404_NOT_FOUND
    
    contact_schema = ContactSchema()
    # 一键序列化Contact对象及其关联数据
    contact_data = contact_schema.dump(contact)
    return jsonify(contact_data), HTTP_200_OK

这种方式的优势是可扩展性强,后续修改模型字段或关联关系时,只需要调整Schema即可,不用手动修改每个路由的序列化逻辑。

内容的提问来源于stack exchange,提问作者user2799827

火山引擎 最新活动