3

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).

simon_dmorias
  • 2,343
  • 3
  • 19
  • 33
  • Why do you use include_relationships = False in the SubmissionSchema, although a relationship exists? It's probably not that simple. Just trying to exclude the seemingly obvious. – above_c_level Aug 05 '20 at 15:34
  • I just tried with both set to same (both ways) - same error. The reason was that for the GET's I wanted Submission to return alone without children, but Policy to return the Parent - do you think that is a bad way to implement? – simon_dmorias Aug 05 '20 at 16:12
  • Makes sense. Unfortunately, the problem is not easy to fix. I have posted a workaround which I have found as an answer. – above_c_level Aug 05 '20 at 17:25

1 Answers1

2

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.

above_c_level
  • 3,579
  • 3
  • 22
  • 37
  • Thank you for this it has worked perfectly. I'm worried about why I ran into this though. Have I done something in an unexpected way? If not I would have expected this to be a very common problem?? I tried to understand the GitHub issue but it was over my head I'm afraid. – simon_dmorias Aug 07 '20 at 07:35
  • As far as I understand it, this is a real issue which simply wasn't fixed due to lack of time of the maintainer. I can't say how common it is; it seems to be an edge case. – above_c_level Aug 07 '20 at 07:46
  • Writing in from 2021 - just checking that this is still the preferred workaround for this? The github issue is still closed – faskiat Oct 29 '21 at 17:43