You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加关联表后Joke数据序列化遇AppenderBaseQuery不可序列化问题

问题

在为Joke模型添加多对多关联表后,使用Marshmallow序列化Joke数据时遇到TypeError: Object of type AppenderBaseQuery is not JSON serializable错误。相关代码及问题详情如下:

模型定义

class Joke(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    joke_name = db.Column(db.String(40), nullable=False)
    joke = db.Column(db.String(5000), nullable=False)
    joke_owner = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    joke_category = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=True)
    joke_created = db.Column(db.DateTime, nullable=True)
    joke_edited = db.Column(db.DateTime, nullable=True)
    tags = db.relationship('JokeTag', secondary=tag_joke, backref=db.backref('jokes', lazy='dynamic'), lazy='dynamic',
            primaryjoin=tag_joke.c.joke_id==id,
            secondaryjoin=tag_joke.c.joketag_id==JokeTag.id)


class JokeTag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tag = db.Column(db.String(25), nullable=False)
    tag_owner = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

关联表定义

tag_joke = db.Table('tag_joke', 
        db.Column('joke_id', db.Integer, db.ForeignKey('joke.id')),
        db.Column('joketag_id', db.Integer, db.ForeignKey('joke_tag.id'))
        )

序列化Schema

class TagJokeSchema(ma.Schema):
    class Meta:
        fields = ('joke_id', 'joketag_id')


class JokeSchema(ma.Schema):
    class Meta:
        fields = ('id', 'joke_name', 'joke', 'joke_owner', 'joke_category', 'joke_created', 'joke_edited', 'tags')

        tags=ma.Nested(TagJokeSchema, many=True)

序列化代码及错误

allnotes = Joke.query.filter_by(joke_owner=1).all()
result = jokes_schema.dump(allnotes)

错误信息:

TypeError: Object of type AppenderBaseQuery is not JSON serializable

另外,打印Joke对象时,tags部分显示为SQL查询语句(因tags是AppenderBaseQuery对象),而调用joke.tags.all()可得到可序列化的标签列表。需要解决序列化时自动使用标签列表,同时优化Joke对象的打印格式。

解决方案

1. 修正Schema的字段定义错误

你的JokeSchema中,tags字段的定义被错误地放在了Meta类内部,这会导致Marshmallow无法识别该字段。需要将其移到类的顶层:

class JokeSchema(ma.Schema):
    # 将tags字段定义移到Meta类外面
    tags = ma.Nested(TagJokeSchema, many=True)
    
    class Meta:
        fields = ('id', 'joke_name', 'joke', 'joke_owner', 'joke_category', 'joke_created', 'joke_edited', 'tags')

2. 处理Dynamic Relationship的序列化

因为你在tags关联中使用了lazy='dynamic',所以joke.tags返回的是AppenderBaseQuery对象而非直接的列表,这就是序列化失败的核心原因。有两种解决方式:

方式一:使用Marshmallow的MethodField手动获取标签列表

在Schema中定义一个方法来主动调用tags.all()获取可序列化的标签列表:

from marshmallow import fields

class JokeSchema(ma.Schema):
    # 用MethodField自定义tags的序列化逻辑
    tags = fields.Method("get_tags")
    
    class Meta:
        fields = ('id', 'joke_name', 'joke', 'joke_owner', 'joke_category', 'joke_created', 'joke_edited', 'tags')
    
    def get_tags(self, obj):
        # 调用all()获取标签列表后再序列化
        tag_schema = TagJokeSchema(many=True)
        return tag_schema.dump(obj.tags.all())

方式二:修改关联的lazy参数(业务允许时)

如果不需要动态查询标签的功能,可以将lazy='dynamic'改为默认的lazy='select',这样joke.tags会直接返回标签列表:

tags = db.relationship('JokeTag', secondary=tag_joke, backref=db.backref('jokes', lazy='dynamic'), lazy='select',
        primaryjoin=tag_joke.c.joke_id==id,
        secondaryjoin=tag_joke.c.joketag_id==JokeTag.id)

修改后,修正字段位置后的原有Schema即可正常序列化。

3. 优化Joke对象的打印格式

为Joke模型添加__repr__方法,自定义打印时的显示内容:

class Joke(db.Model):
    # 原有字段定义...
    
    def __repr__(self):
        return f"<Joke(id={self.id}, name='{self.joke_name}', owner={self.joke_owner}, tags={[tag.tag for tag in self.tags.all()]})>"

这样打印Joke对象时,会显示ID、名称、所有者以及标签内容列表,而非默认的SQL查询语句。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:51:01