SQLAlchemy 多态关联
我正在尝试通过SQLAlchemy库实现多态关联,并使用了一个示例:
不过,这个示例和我的情况有些不兼容。在这个示例中,地址对象(Address)是先创建的,然后再将它们添加到供应商(Supplier)或客户(Customer)中(所以地址表有一个多态的外键指向供应商和客户表,而供应商和客户对象则可以通过反向引用来访问地址)。当地址对象被添加到这两个表中的一个时,SQLAlchemy会自动处理如何在这些表中分配ID。然后,可以通过地址的“parent”字段获取到供应商或客户对象。
但是在我的情况下,我需要先创建地址对象,然后再将一个对象(例如公司)分配给这个地址的父对象(在示例中是供应商和客户)。
这是我案例中使用多态关联的示例:
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = Session(engine)
address = Address(street='2569 west elm', city="Detroit", zip="56785")
cust = Customer(name="Tester")
supl = Supplier(company_name="Ace Hammers")
address.parent = supl
session.add_all([address])
session.commit()
但是如果我尝试将这个模式直接应用到我的情况中而不进行修改,我会收到以下错误信息:
Traceback (most recent call last): File "discriminator_on_related.py", line 131, in address.parent = supl File "C:\Python27\lib\site-packages\sqlalchemy-0.9.3-py2.7-win32.egg\sqlalchemy\ext\associationproxy.py", line 271, in __set__ setattr(obj, self.target_collection, creator(values)) TypeError: __init__() takes exactly 1 argument (2 given)
我应该如何修改这个模式才能让它正常工作呢?
附注:抱歉如果这个问题很简单(对我来说,SQLAlchemy的association_proxy看起来有点神奇)。
1 个回答
25
抱歉打扰到大家了。也许这个答案对某些人会有帮助。其实答案真的很简单。我最大的错误是用一个复杂的例子作为我的基础。要解决这个问题,只需要把它拆分成几个小任务。所以这个任务主要涉及多态继承和连接表(用SQLAlchemy实现起来相当简单),以及在公共(父)表上设置外键。下面是相关的代码片段:
@as_declarative()
class Base(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
id = Column(Integer, primary_key=True)
class CompanyInterface(Base):
discriminator = Column(String)
__mapper_args__ = {"polymorphic_on": discriminator}
class Address(Base):
street = Column(String)
city = Column(String)
zip = Column(String)
company_id = Column(Integer, ForeignKey(CompanyInterface.id))
company = relationship(CompanyInterface)
def __repr__(self):
return ("%s(street=%r, city=%r, zip=%r, company=%r)" %
(self.__class__.__name__, self.street, self.city, self.zip, self.company))
class Customer(CompanyInterface):
id = Column(Integer, ForeignKey(CompanyInterface.id), primary_key=True)
name = Column(String)
__mapper_args__ = {"polymorphic_identity": "Customer"}
class Supplier(CompanyInterface):
id = Column(Integer, ForeignKey(CompanyInterface.id), primary_key=True)
company_name = Column(String)
__mapper_args__ = {"polymorphic_identity": "Supplier"}
engine = create_engine('sqlite:///test/test_me.db', echo=False)
Base.metadata.create_all(engine)
session = Session(engine)
address1 = Address(street='test-1', city="Detroit", zip="56785")
address2 = Address(street='test-2', city="Phoenix", zip="110322")
address3 = Address(street='test-3', city="Washington", zip="432414")
supl1 = Supplier(company_name="Supplier-1 TEST")
supl2 = Supplier(company_name="Supplier-2 TEST")
cust1 = Customer(name="Customer-1 TEST")
cust2 = Customer(name="Customer-2 TEST")
address1.company = supl1
address2.company = cust1
address3.company = cust1
session.add_all([address1, address2, address3])
session.commit()
address3.company = supl2
session.commit()
print "PRINTING, TOTAL = %s" % session.query(Address).count()
for address in session.query(Address):
print "ADDRESS = %s" % address