#python #flask #sqlalchemy #marshmallow
#python #flask #sqlalchemy #marshmallow
Вопрос:
Я пытаюсь десериализовать глубокую структуру с помощью marshmallow. Например:
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'
Обратите внимание, что та же схема работает для десериализации той же структуры данных (hour), когда эта структура не вложена внутри 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')
Обновить:
Я думаю, что происходит то, что marshmallow не пытается десериализовать HoursDay
объект при попытке десериализовать new_practitioner_at_location
dict. Если я удалю backpopulates
поведение из HoursDay.hour
поля, вы сможете увидеть, что это просто присваивает полю несериализованную структуру данных. Для меня это вообще не имеет смысла, тем более что это работает, когда вы просто десериализуете hour
dict напрямую, вместо того, чтобы встраивать его внутрь new_practitioner_at_location
. Любая помощь была бы оценена.
Комментарии:
1. К вашему сведению, ваш автономный скрипт не запускается как есть, поскольку он пытается загрузить конфигурацию из env var и не создает таблицы db.
Ответ №1:
Это простая ошибка, похожая на опечатку:
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)
Комментарии:
1. Вау. Вы наблюдаете один из самых сложных фейспалмов, которые я когда-либо делал.