Десериализация зефира терпит неудачу, когда структура вложена - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь десериализовать глубокую структуру с помощью зефира.Например:

hour = {
    'day': {
        'name': 'monday'
    }
}
loaded_hour, error = HoursSerializationSchema().load(hour) # this works

new_practitioner_at_location = {
    'hours': [
        hour
    ]
}
loaded, error = PractitionerToServiceLocationSerializationSchema().load(new_practitioner_at_location) # this fails

Когда я пытаюсь десериализовать new_practitioner_at_location, я получаю следующее (происходит, когда сериализатор работает над клавишей 'day'):

AttributeError: 'dict' object has no attribute '_sa_instance_state'

Обратите внимание, что одна и та же схема работает для десериализации той же самой структуры данных (час), когда эта структура не вложена в автономный скрипт new_practitioner_at_location.

, показывающий проблему:

from sqlalchemy import Column, Integer, ForeignKey, String
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate

base = declarative_base()


class HoursDay(base):
    __tablename__ = 'HoursDay'
    uid = Column(Integer, primary_key=True)

    name = Column(String)

    hour_id = Column(Integer, ForeignKey('Hours.uid'))
    hour = relationship("Hours", back_populates="day")

    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class Hours(base):
    __tablename__ = 'Hours'
    uid = Column(Integer, primary_key=True)

    practitioner_at_location_id = Column(Integer, ForeignKey('PractitionerToServiceLocation.uid'))
    practitioner_at_location = relationship('PractitionerToServiceLocation', back_populates="hours")

    day = relationship(HoursDay, uselist=False, back_populates="hour")

    def __repr__(self):
        return f'<Hours {self.uid}>'


class PractitionerToServiceLocation(base):
    """
    A practitioner practices at a number of service locations.
    """
    __tablename__ = 'PractitionerToServiceLocation'
    uid = Column(Integer, primary_key=True)

    hours = relationship("Hours", back_populates="practitioner_at_location")

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def __repr__(self):
        return f'<PractitionerToServiceLocation {self.uid}>'


app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
db = SQLAlchemy(app, model_class=base)
ma = Marshmallow(app)
migrate = Migrate(app, db)

from marshmallow import fields


class HoursDaySerializationSchema(ma.ModelSchema):
    class Meta:
        model = HoursDay


class HoursSerializationSchema(ma.ModelSchema):
    class Meta:
        model = Hours

    day = fields.Nested(HoursDaySerializationSchema)


class PractitionerToServiceLocationSerializationSchema(ma.ModelSchema):
    class Meta:
        model = PractitionerToServiceLocation

        hours = fields.Nested('HoursSerializationSchema', many=True)


if __name__ == "__main__":
    hour = {
        'day': {
            'name': 'monday'
        }
    }
    loaded_hour, error = HoursSerializationSchema().load(hour) # this works

    new_practitioner_at_location = {
        'hours': [
            hour
        ]
    }
    loaded, error = PractitionerToServiceLocationSerializationSchema().load(new_practitioner_at_location) # this fails
    print('hi')

Обновление:

Я думаю, что происходит то, что зефир не пытается десериализовать объект HoursDay, когда пытается десериализовать диктат new_practitioner_at_location.Если я уберу поведение backpopulates из поля HoursDay.hour, вы увидите, что оно просто присвоило этой структуре несериализованную структуру данных.Для меня это не имеет никакого смысла, тем более что это работает, когда вы просто десериализуете диктат hour напрямую, а не внедряете его в new_practitioner_at_location.Любая помощь будет оценена.

1 Ответ

4 голосов
/ 19 марта 2019

Это простая опечатка:

class PractitionerToServiceLocationSerializationSchema(ma.ModelSchema):
    class Meta:
        model = PractitionerToServiceLocation

        hours = fields.Nested('HoursSerializationSchema', many=True)

Вы определяете hours внутри class Meta, но оно должно быть в самой вашей схеме:

class PractitionerToServiceLocationSerializationSchema(ma.ModelSchema):
    class Meta:
        model = PractitionerToServiceLocation

    hours = fields.Nested('HoursSerializationSchema', many=True)
...