Сериализовать две вложенные схемы с зефиром

Я довольно новичок в питоне. У меня есть две модели SQLAlchemy следующим образом:

class listing(db.Model):
 id = db.Integer(primary_key=True)
 title = db.String()
 location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
 location = db.relationship('Location', lazy='joined')

class location(db.Model):
 id = db.Integer(primary_key=True)
 title = db.String()

У меня есть два класса схемы Marshmallow для них:

class ListingSchema(Schema):
 id = fields.Int()
 title = fields.Str()
 location_id = fields.Int()

class LocationSchema(Schema):
 id = fields.Int()
 title = fields.Str()

Я создал вложенный класс схемы, например:

class NestedSchema(Schema):
 listing = fields.Nested(ListingSchema)
 location fields.Nested(LocationSchema)

Я делаю запрос на соединение, например:

listing,location = db.session.query(Listing,Location)\
                            .join(Location, and_(Listing.location_id == Location.id))\
                            .filter(Listing.id == listing_id).first()

данные загружаются в объекты, которые я проверил. Как разобрать эту схему? я пытался

result,errors = nested_listing_Schema(listing,location)

Это дает ошибку: «Объект листинга не является итерируемым».


person Sohaib Farooqi    schedule 04.09.2016    source источник
comment
Показать источник для nested_listing_Schema   -  person Moses Koledoye    schedule 04.09.2016


Ответы (1)


Правильно использовать созданный вами класс NestedSchema, а не nested_schema, сделайте так:

result,errors = NestedSchema().dump({'listing':listing,'location':location})

И результатом будет:

dict: {
       u'listing': {u'id': 8, u'title': u'foo'},
       u'location': {u'id': 30, u'title': u'bar'}
      }

Но я не понимаю, почему вы хотели сделать «вложенную схему», я думаю, вы можете сделать это по-другому.

Во-первых, забудьте о классе "NestedSchema".

После этого измените свою «ListingSchema» следующим образом:

class ListingSchema(Schema):
    id = fields.Int()
    title = fields.Str()
    location_id = fields.Int()
    location = fields.Nested("LocationSchema") #The diff is here

И теперь вы можете сделать:

listing = db.session.query(Listing).get(listing_id) # Suppose listing_id = 8
result,errors = ListingSchema().dump(listing)
print result

Результат будет:

dict: {
        u'id': 8, u'title': u'foo', u'location_id': 30, u'location': {u'id': 30, u'title': u'bar'}
      }

Обратите внимание, что теперь «местоположение» является свойством «списка».

И вы по-прежнему можете сделать двустороннее вложение, просто добавьте обратную ссылку в Listing (модель) и добавьте ListingSchema как вложенную в LocationSchema.

class Listing(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(45), nullable=False)
    location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
    location = db.relationship('Location', lazy='joined', backref="listings") #the diff is here

class LocationSchema(Schema):
    id = fields.Int()
    title = fields.Str()
    listings = fields.Nested("ListingSchema", many=True, exclude=("location",)) #The property name is the same as in bakcref

many=True — это потому, что у нас есть отношения «один ко многим». exclude=("location") чтобы избежать исключения рекурсии.

Теперь мы можем искать и по местоположению.

location = db.session.query(Location).get(location_id) # Suppose location_id = 30
result,errors = LocationSchema().dump(location)
print result

dict: {u'id': 30, u'title': u'bar', 
       u'listings': [
             {u'location_id': 30, u'id': 8, u'title': u'foo'},
             {u'location_id': 30, u'id': 9, u'title': u'foo bar baz'},
             ...
             ]
       }

Вы можете ознакомиться с документацией по этому поводу здесь

person Jair Perrut    schedule 28.09.2016