Как сгруппировать поля при сериализации объекта с Зефиром? - PullRequest
1 голос
/ 25 марта 2020

Проблема

Как группировать поля при сериализации плоско структурированного объекта SQLAlchemy с помощью Marshmallow без изменения плоской структуры данных в фоновом режиме?

Пример

Предположим, что a Модель SQLAlchemy в приложении Flask выглядит следующим образом:

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 и y были вложены в coordinates, сохраняя при этом плоскую структуру данных в фон (модель)? Вывод должен выглядеть примерно так:

{
  "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()

Наличие этого на месте поднимает проблему необходимости go через каждый Data и добавляем вручную схему Coordinates. Мои данные поступают из запроса SQLAlchemy, возвращающего список Data объектов, так что я могу легко вывести их, используя schema_datas.

Используя fields.Dict

С Marshmallows fields Модуль предлагает словарь, я тоже пробовал.


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

Кажется, тоже не работает, потому что Зефир не может автоматически найти Data.x и Data.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)

Но, к сожалению, это тоже не сработало.

Использование Decorator @pre_dump

Inspired эта проблема на странице Github Marshmallow , я попытался использовать декоратор @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
    }

Но я не могу понять, как чтобы сделать это правильно ...


Итак, мой вопрос, что я делаю не так и как я могу решить эту проблему?

...