我正在使用SQLAlchemy映射数据库,该数据库具有多个“错误”多对多关系的情况。我的意思是,假设我有以下对象:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
addresses = relationship('Address', secondary='user_address')
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
users = relationship('User', secondary='user_address')
class UserAddressLink(Base):
__tablename__ = 'user_address'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
address_id = Column(Integer, ForeignKey('address.id'))
所以,一个简单的多对多关系吧?但有一个问题:它从来没有打算成为多对多的。这实际上是一对一的关系,无论出于何种原因,有人决定在数据库中设计这样的关系。每Address
只有一个User
,反之亦然。我无法控制数据库设计(事实上,我只是从这个数据库中读取而从不写在上面)所以我无法改变它。
在SQLAlchemy上有没有一种标准的处理方式?它会自动假定这是一个多对多关系,并将User.adresses和Address.users视为列表。
我正在处理它的方式是创建属性:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
_addresses = relatioship('Address', secondary='user_address')
@property
def address(self):
return self.addresses[0] if len(self.addresses) > 0 else None
@address.setter
def address(self, value):
self.addresses = [value]
等等。
这是处理此问题的最佳方式还是有其他解决方法?
答案 0 :(得分:1)
通过在One-to-One relationship定义中使用uselist = False
来定义这种关系有一种非常简单的方法:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
# other columns
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
# other columns
name = Column(String)
# relationship(
user = relationship(
User,
secondary='user_address',
uselist=False,
backref=backref('address', uselist=False),
)
user_address = Table(
'user_address', Base.metadata,
Column('id', Integer, primary_key=True),
Column('use_id', Integer, ForeignKey('user.id')),
Column('address_id', Integer, ForeignKey('address.id')),
)
然后您可以根据需要使用代码:
# add some data
u1 = User(name='JJ', address=Address(name='superstreet'))
a2 = Address(name='LA')
a2.user = User(name='John')
session.add(u1)
session.add(a2)
session.commit()
session.expunge_all()
# get users and preload addresses as well in one query
q = session.query(User).options(joinedload(User.address))
for u in q.all():
print(u)
print(" {}".format(u.address))
关于代码的更多注释:
backref
来实现这个user_address
表定义整个映射类,上面的表定义是