Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing a sqlalchemy hybrid_property using marshmallow

I am using sqlalchemy and marshmallow in my RESTful flask application to serialize my models. I have a hybrid_property that comes from one of my relationships on that model. I would like to now serialize that hybrid_property in my schema using the schema from the related model.

Has anyone done this before? Here are my relevant pieces of code. It doesn't seem to be including the last_assessment in the serialized version of the model when I check the response

class Person(db.Model):
  daily_rula_average_ranges = db.relationship('DailyRulaAverageRange', order_by="DailyRulaAverageRange.date", back_populates='person')

  @hybrid_property
  def last_assessment(self):
    if self.daily_rula_average_ranges.length > 0:
      return self.daily_rula_average_ranges[-1]

class PersonSchema(ma.Schema):
  last_assessment = ma.Nested(DailyRulaAverageRangeSchema, only=['id', 'date', 'risk'])
  class Meta:
    fields = ('last_assessment')
like image 314
James Russo Avatar asked Jun 01 '18 20:06

James Russo


1 Answers

It's a bit sneaky, but I believe the problem is that the line if self.daily_rula_average_ranges.length > 0: is causing an AttributeError to be raised, because length is not usually an attribute of lists. You probably meant if len(self.daily_rula_average_ranges) > 0: .

Here's an ORM-agnostic example - the serializer returns no field if an attribute error is raised, but returns data fine if appropriate data is returned by the property:

from marshmallow import fields, Schema
from marshmallow.fields import Nested

class DailyRulaAverageRangeSchema(Schema):
    id=fields.UUID()
    date=fields.Date()
    risk=fields.Integer()

class PersonSchema(Schema):
    last_assessment = Nested(DailyRulaAverageRangeSchema, only=['id', 'date', 'risk'])
    class Meta:
        fields = ('last_assessment',)

class Person(object):
    @property
    def last_assessment(self):
        raise AttributeError('oops')

PersonSchema().dump(Person())

# Out[73]: {}

class Person(object):
    @property
    def last_assessment(self):
        return {"id": None, "date":None, 'risk': 100}   

PersonSchema().dump(Person())
# Out[83]: {u'last_assessment': {u'date': None, u'id': None, u'risk': 100}}

It is not too surprising that marshmallow behaves this way because an attribute that raises an AttributeError will appear as though the attribute does not exist, e.g.:

class Person(object):
    @property
    def last_assessment(self):
        raise AttributeError('oops')

hasattr(Person(), 'last_assessment')
# Out: False
like image 129
Michael Nelson Avatar answered Oct 31 '22 10:10

Michael Nelson