Вложенная десериализация SQLAlchemyAutoSchema - PullRequest
1 голос
/ 05 августа 2020

У меня есть следующее:

Models.py

class Policy(db.Model):
    policy_id = db.Column(db.Integer, primary_key=True)
    client_reference = db.Column(db.String(50), nullable=False)
    submission_id = db.Column(db.ForeignKey('submission.submission_id'), nullable=False)

    submission = relationship("Submission", back_populates="policies", lazy='joined')


class Submission(db.Model):
    submission_id = db.Column(db.Integer, primary_key=True)
    client_reference = db.Column(db.String(50), nullable=False)

    policies = db.relationship('Policy', back_populates='submission', lazy='joined')

Schema.py

class PolicySchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Policy
        include_relationships = True
        load_instance = True
        unknown = INCLUDE
        exclude = ("submission",)

    submission_id = auto_field("submission")


class SubmissionSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Submission
        include_relationships = False
        load_instance = True

    policies = fields.Nested(PolicySchema, many=True, allow_none=True)

routes.py

@submission_api.route('/submission/', methods=['POST'])
def add_new():
    body = request.get_json()
    validated_request = SubmissionSchema().load(body, session=db.session)
    db.session.add(validated_request)
    db.session.commit()
    return jsonify({"submission_id": validated_request.submission_id}), 200

Если я попытаюсь добавить новую запись в Представление, используя:

{
    "client_reference": "POL1",
    "description": "hello"
}

Он работает правильно.

Если я позвоню с помощью:

{
    "client_reference": "POL1","description": "hello",
    "policies": [{"client_reference": "A1"}]
}

, я получаю эту ошибку:

File "/usr/local/lib/python3.8/site-packages/marshmallow_sqlalchemy/schema/load_instance_mixin.py", line 89, in load
    raise ValueError("Deserialization requires a session")
ValueError: Deserialization requires a session

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

1 Ответ

1 голос
/ 05 августа 2020

Боюсь, что нет только реального решения, просто обходной путь, обсуждаемый в этой проблеме github . Процитируем TMiguelIT :

Разве для нас не было бы разумным создать собственное поле Nested, которое наследуется от исходного Marshmallow Nested, позволяя нам передавать объект сеанса вниз? Будет ли это dimini sh юзабилити каким-либо образом?

Насколько я понимаю, решение должно выглядеть примерно так:

from marshmallow import fields

class Nested(fields.Nested):
    """Nested field that inherits the session from its parent."""

    def _deserialize(self, *args, **kwargs):
        if hasattr(self.schema, "session"):
            self.schema.session = db.session  # overwrite session here
            self.schema.transient = self.root.transient
        return super()._deserialize(*args, **kwargs)

Итак, вы создаете свой Nested (я только что скопировал код из marshmallow-sqlalchemy) вверху schemy.py и перезаписал сеанс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...