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

求助:Marshmallow嵌套序列化时如何携带父字段(Flask+Peewee)

解决方案:给Marshmallow嵌套对象添加父级字段

嘿,我刚好在维护Flask+Marshmallow+Peewee项目时遇到过几乎一模一样的需求!下面分**反序列化(接收客户端数据)和序列化(输出JSON)**两个场景给你讲清楚可行的实现方式:

场景1:反序列化时,将父级字段关联到嵌套子对象

当你接收客户端传来的JSON时,需要把父级的site_id、update_date等字段关联到data数组里的每个子项对应的Peewee模型实例,最方便的方式是用Marshmallow的post_load钩子:

第一步:定义Peewee模型

假设你的模型结构是这样的(父模型和子模型通过外键关联):

from peewee import Model, CharField, DateTimeField, ForeignKeyField, IntegerField
import datetime

# 父级模型:对应客户端JSON的顶层字段
class SiteUpdate(Model):
    site_id = CharField()
    update_date = DateTimeField()
    updated_by = CharField()
    crc = CharField()

# 子级模型:对应data数组里的每个对象
class SiteData(Model):
    site_update = ForeignKeyField(SiteUpdate, backref='data')  # 外键关联父模型
    num = IntegerField()
    id = CharField()
    chain = CharField()
    # 其他字段根据你的需求补充

第二步:编写Marshmallow Schema并添加post_load钩子

在父级Schema的post_load方法里,先创建并保存父模型实例,再遍历data数组给每个子对象绑定父模型:

from marshmallow import Schema, fields, post_load

class SiteDataSchema(Schema):
    num = fields.Integer()
    id = fields.Str()
    chain = fields.Str()
    # 子Schema只需要定义自身的字段,父级关联通过钩子处理

class SiteUpdateSchema(Schema):
    site_id = fields.Str()
    # 注意匹配客户端的日期格式,确保能正确解析
    update_date = fields.DateTime(format='%Y/%m/%d-%H:%M:%S')
    updated_by = fields.Str()
    crc = fields.Str()
    data = fields.Nested(SiteDataSchema, many=True)

    @post_load
    def bind_parent_to_children(self, data, **kwargs):
        # 1. 先创建并保存父模型实例(必须先保存才能拿到主键用于外键关联)
        site_update = SiteUpdate(
            site_id=data['site_id'],
            update_date=data['update_date'],
            updated_by=data['updated_by'],
            crc=data['crc']
        )
        site_update.save()

        # 2. 遍历data数组,给每个子对象绑定父模型并保存
        for item in data['data']:
            site_data = SiteData(
                site_update=site_update,
                num=item['num'],
                id=item['id'],
                chain=item['chain']
                # 补充其他子字段
            )
            site_data.save()
        
        return site_update

这样,当你调用SiteUpdateSchema().load(client_json_data)时,就能自动完成父模型和子模型的关联存储。

场景2:序列化时,让嵌套子对象携带父级字段

如果是把数据库中的模型数据序列化成JSON输出,需要让data数组里的每个子对象带上父级的site_id等字段,有两种简单的实现方式:

方式一:在子Schema中用MethodField获取父级字段

直接在子Schema里定义需要携带的父级字段,通过MethodField从关联的父模型中取值:

class SiteDataSchema(Schema):
    num = fields.Integer()
    id = fields.Str()
    chain = fields.Str()
    # 添加需要携带的父级字段
    site_id = fields.Method("get_parent_site_id")
    update_date = fields.Method("get_parent_update_date")
    updated_by = fields.Method("get_parent_updated_by")
    crc = fields.Method("get_parent_crc")

    def get_parent_site_id(self, obj):
        return obj.site_update.site_id
    
    def get_parent_update_date(self, obj):
        # 转成客户端需要的日期格式
        return obj.site_update.update_date.strftime('%Y/%m/%d-%H:%M:%S')
    
    def get_parent_updated_by(self, obj):
        return obj.site_update.updated_by
    
    def get_parent_crc(self, obj):
        return obj.site_update.crc

class SiteUpdateSchema(Schema):
    site_id = fields.Str()
    update_date = fields.DateTime(format='%Y/%m/%d-%H:%M:%S')
    updated_by = fields.Str()
    crc = fields.Str()
    data = fields.Nested(SiteDataSchema, many=True)

方式二:在父Schema中用post_dump钩子批量注入父级字段

如果不想修改子Schema,可以在父Schema的post_dump方法里,把父级字段批量添加到每个子对象中:

class SiteDataSchema(Schema):
    num = fields.Integer()
    id = fields.Str()
    chain = fields.Str()
    # 子Schema保持原有定义即可

class SiteUpdateSchema(Schema):
    site_id = fields.Str()
    update_date = fields.DateTime(format='%Y/%m/%d-%H:%M:%S')
    updated_by = fields.Str()
    crc = fields.Str()
    data = fields.Nested(SiteDataSchema, many=True)

    @post_dump
    def inject_parent_fields_to_children(self, data, **kwargs):
        # 提取父级需要传递的字段
        parent_fields = {
            'site_id': data['site_id'],
            'update_date': data['update_date'],
            'updated_by': data['updated_by'],
            'crc': data['crc']
        }
        # 给每个子对象添加父级字段
        for item in data['data']:
            item.update(parent_fields)
        return data

两种方式都能实现需求,方式一更灵活(可以单独控制每个父级字段的输出逻辑),方式二更简洁(不需要修改子Schema)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:24:12