[英]How can I create declarative relationship to multiple tables in SQLAlchemy (polimorphic)
如何在SQLAlchemy(策略化)中創建與多個表的聲明關系?
我有Journal對象,該對象反映數據庫中的日記表。 它在相關表中保存類型和ID(作為外鍵)。 我需要創建聲明性的類來映射此表。
我無法更改數據庫的結構,也無法創建其他關聯表。 但是我知道對象的標識符。
我想要得到的是您可以在代碼示例的底部看到的。
engine = create_engine('sqlite://', echo=True)
metadata = MetaData(bind=engine)
Base = declarative_base(bind=metadata)
DBSession = sessionmaker(bind=engine, autocommit=False, expire_on_commit=False)
session = DBSession()
class Person(Base):
__abstract__ = True
class Manager(Person):
__tablename__ = 'managers'
identifier = '01'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
'polymorphic_identity': identifier,
}
class Engineer(Person):
__tablename__ = 'engineers'
identifier = '02'
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
'polymorphic_identity': identifier,
}
class Journal(Base):
__tablename__ = 'journal'
identifier = '03'
id = Column(Integer, primary_key=True)
date = Column(Date)
type = Column(String(50))
person_id = Column(Integer)
person = relationship() # can’t figure out this relationship
__mapper_args__ = {
'polymorphic_on': type,
'with_polymorphic': '*'
}
if __name__ == '__main__':
metadata.create_all()
en1 = Engineer(id=1)
mn1 = Manager(id=2)
session.add_all([en1, mn1])
session.commit()
j1 = Journal(person=en1)
# -> INSERT INTO Journal (type, person_id) VALUES (’02’, 1)
j2 = Journal(person=mn1)
# -> INSERT INTO Journal (type, person_id) VALUES (‘01’, 2)
for row in session.query(Journal):
print(row, row.person)
# -> [<Journal …>, <Manager …>]
# -> [<Journal …>, <Engineer …>]
for row in session.query(Journal).filter(Journal.type == Manager.identifier):
print(row, row.person)
# -> [<Journal …>, <Manager …>]
感謝Mike Bayer的文章找到了解決方案。
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
identifier = '01'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
class Order(Base):
__tablename__ = 'orders'
identifier = '02'
id = Column('id', Integer, primary_key=True)
description = Column('description', String(50), nullable=False)
class Address(Base):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True)
addressable_id = Column('addressable_id', Integer)
addressable_type = Column('addressable_type', String(50))
street = Column('street', String(100))
city = Column('city', String(50))
country = Column('country', String(50))
def __init__(self, type):
self.addressable_type = type
member = property(lambda self: getattr(self, '_backref_%s' % self.addressable_type))
def addressable(cls, name, uselist=True):
"""addressable 'interface'."""
def create_address(self):
a = Address(cls.identifier)
if uselist:
getattr(self, name).append(a)
else:
setattr(self, name, a)
return a
cls.create_address = create_address
mapper = class_mapper(cls)
table = mapper.local_table
# no constraints. therefore define constraints in an ad-hoc fashion.
primaryjoin = and_(
list(table.primary_key)[0] == Address.addressable_id,
Address.addressable_type == cls.identifier
)
foreign_keys = [Address.addressable_id]
mapper.add_property(name, relation(
Address,
primaryjoin=primaryjoin, uselist=uselist, foreign_keys=foreign_keys,
backref=backref(
'_backref_%s' % cls.identifier,
primaryjoin=list(table.primary_key)[0] == Address.addressable_id,
foreign_keys=foreign_keys,
# lazy="joined" # Joined strategy
)
)
)
addressable(User, 'addresses', uselist=True)
addressable(Order, 'address', uselist=False)
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
u1 = User()
u1.name = 'bob'
o1 = Order()
o1.description = 'order 1'
a1 = u1.create_address()
a1.street = '123 anywhere street'
a2 = u1.create_address()
a2.street = '345 orchard ave'
a3 = o1.create_address()
a3.street = '444 park ave.'
sess = create_session(bind=e)
sess.add(u1)
sess.add(o1)
sess.flush()
# query addresses and get relative objects
for address in sess.query(Address):
print("Street", address.street, "Member", address.member)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.