1

问题

使用 Marshmallow 序列化平面结构的 SQLAlchemy 对象时如何将字段组合在一起而不更改后台的平面数据结构?

例子

假设 Flask 应用程序中有一个 SQLAlchemy 模型,如下所示:

from app import db # db using SQLAlchemy

class Data(db.Model):
  x = db.Column(db.Float(), required=True)
  y = db.Column(db.Float(), required=True)
  d = db.Column(db.Float())

如何序列化这个对象,以便x嵌套ycoordinates中,同时在后台(模型)中保持平面数据结构?输出应如下所示:

{
  "coordinates": {
    "x": 10.56
    "y": 1
  },
  "d": 42.0
}

问题之所以出现,是因为我使用带有选项的Data架构。many=True初始化大致是:

schema_data = MomentData()
schema_datas = MomentData(many=True)

解决方案候选者

所以这是我迄今为止尝试过的,但它们似乎都没有奏效。

创建第二个架构

添加第二个模式并Data从之前修改模式会产生:

class CoordinatesSchema(Schema):
  x = fields.Float(required=True)
  y = fields.Float(required=True)

class DataSchema(Schema):
  coordinates = fields.Nested(coordinatesSchema, required=True)
  d = fields.Float()

有了它会引发必须遍历每个Data项目并手动添加Coordinates架构的问题。我的数据来自返回Data对象列表的 SQLAlchemy 查询,因此我可以使用schema_datas.

使用fields.Dict

由于 Marshmallowsfields模块提供了字典,所以我也尝试过。


def DataSchema(Schema):
  coordinates = fields.Dict(keys=fields.String(),
                            value=fields.Float(),
                            required=True,
                            default={
                                 "x": Data.x,
                                 "y": Data.y
                            })
  d = fields.Float()

似乎也不起作用,因为 MarshmallowData.xData.y使用schema_datas.dump().

使用自嵌套

最合乎逻辑的解决方案是自嵌套。但是(根据我阅读文档的理解)自嵌套仅指在对象中嵌套一个或多个其他实例。我想嵌套同一个实例。

class DataSchema(Schema):
  x = fields.Float(required=True, load_only=True)
  y = fields.Float(required=True, load_only=True)

  coordinates = fields.Nested(
        lambda: DataSchema(only=('x', 'y')),
        dump_only=True)

但不幸的是,这也没有奏效。

使用装饰器@pre_dump

Marshmallow 的 Github 页面上这个问题的启发,我尝试使用@pre_dump装饰器来达到预期的结果,但又失败了。


class CoordinatesSchema(Schema):
  x = fields.Float(required=True)
  y = fields.Float(required=True)

class DataSchema(Schema):
  coordinates = fields.Nested(coordinatesSchema, required=True)
  d = fields.Float()

  @pre_dump
  def group_coordinates(self, data, many):
    return {
      "coordinates": {
        "x": data.x,
        "y": data.y
        },
      "d": data.d
    }

但我无法弄清楚如何正确地做到这一点......


所以我的问题是,我做错了什么,我该如何解决这个问题?

4

0 回答 0