如何通过自定义setter和/或getter扩充sqlalchemy关系

时间:2016-06-22 13:41:50

标签: python sqlalchemy relationship

我需要与自定义getter和setter建立关系。 在关系声明上定义setter / getter参数会很好 即使没有数据连接,我也需要改变关系getter(即将None更改为更复杂的东西)

这大致是我需要的:

class Address(Base):
    #...

    #hybrid attributes? custom class instrumentation? I need call this function even if no rows are joined to user or company
    def getter(self):
         #for each joined row
         return {'address': "%s %s" % (self.cilty, self.country), 'maximum' : some_data['maximum']}
         #if no row joined
         return {'address': None, 'maximum' : some_data['maximum']}

    def setter(self, user):
         if some_data['only_country'] != user.country:
             raise Exception('You can`t live in %s. sorry', (user.country,))
         self.country = user.country

class User(Base):
    #...
    addresses = relationship(Address, some_data = {'maximum': 1, only_country: 'UA'})

class Company(Base):
    #...
    addresses = relationship(Address, some_data = {'maximum': 7, only_country: 'US'})

现在我想使用以下关系

u = db.query(User).filter_by(id=1).one()
# I need data from getter here
print(u.address)

u = User()
# I need setter called here with references to user and some_data defined in relationship definition
u.address = Address()

1 个答案:

答案 0 :(得分:0)

最佳解决方案是使用association_proxy

对于提供的示例解决方案,如下所示:

class AddressAssociation:

    some_data = {}

    def setter(self, AddressObject, value):
        # change AddressObject here depend on value and self.some_data

    def getter(self, AddressObject):
        # return something depend on AddressObject and self.some_data

    def creator(self, value):
        # return Address() depend on value and self.some_data

    def __init__(self, some_data):
        self.some_data = some_data

    def get_proxy(self, target_name):
        return association_proxy(target_name, None,
            creator=self.creator,
            getset_factory=lambda *a, **kwa: self.getter, self.setter)

class User(Base):
    #...
    addresses_relationship = relationship(Address)
    addresses = AddressAssociation({'maximum': 1, 'only_country': 'UA'}).get_proxy('addresses_relationship')

u = User() # AddressAssociation.creator called
u.addresses = something # AddressAssociation.creator called
print(u.addresses) # AddressAssociation.getter called
u.addresses = something_else # AddressAssociation.setter called