添加关联表后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
相关产品推荐
相关产品推荐

