I have the following:
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
If I try to add a new record into Submission using:
{
"client_reference": "POL1",
"description": "hello"
}
It works correctly.
If I call with:
{
"client_reference": "POL1","description": "hello",
"policies": [{"client_reference": "A1"}]
}
I receieve this error:
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
I can't figure out why. I pass the session in the same way for both (its the same function). I've made a change to cause this because it was working (reminder to commit code more often).
I am afraid there is no real solution only, just a workaround discussed in this github issue. To quote TMiguelIT:
Would it not be reasonable for us to create our own Nested field that inherits from the original Marshmallow Nested, allowing us to pass the session object down? Would this diminish usability in any way?
As I understand it, the solution should look something like this:
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)
So you create your own Nested
field (I just copied the code from marshmallow-sqlalchemy) at the top of schemy.py
and overwrite the session.