Python SQLAlchemy中具有多个父项的泛型关联

Python SQLAlchemy中具有多个父项的泛型关联,python,sqlalchemy,Python,Sqlalchemy,我正在尝试了解SQLAlchemy附带的“”示例,该示例定义了HasAddresses mixin,因此每个HasAddresses子类化的模型都会神奇地获得一个addresses属性,这是一个可以添加地址对象的集合。链接是通过一个中间表执行的,因此乍一看,这种关系就像是多对多,我希望能够将多个地址链接到一个客户,也可以将多个客户和供应商链接到一个地址 然而,地址模型的设置方式是,它有一个只能引用单个对象的父属性。因此,在本例中,地址只能链接到单个客户或供应商 如何修改该示例,使Address能

我正在尝试了解SQLAlchemy附带的“”示例,该示例定义了HasAddresses mixin,因此每个HasAddresses子类化的模型都会神奇地获得一个
addresses
属性,这是一个可以添加地址对象的集合。链接是通过一个中间表执行的,因此乍一看,这种关系就像是多对多,我希望能够将多个地址链接到一个客户,也可以将多个客户和供应商链接到一个地址

然而,
地址
模型的设置方式是,它有一个只能引用单个对象的
父属性。因此,在本例中,地址只能链接到单个客户或供应商


如何修改该示例,使Address能够反向引用多个父对象

我们可以修改sqlalchemy/examples/generic_associations/table_per_association.py,在Address中添加一个命名的backref,然后添加一个@property,该@property汇总所有创建的backref

"""table_per_association.py

The HasAddresses mixin will provide a new "address_association" table for
each parent class.   The "address" table will be shared
for all parents.

This configuration has the advantage that all Address
rows are in one table, so that the definition of "Address"
can be maintained in one place.   The association table 
contains the foreign key to Address so that Address
has no dependency on the system.


"""
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy import create_engine, Integer, Column, \
                    String, ForeignKey, Table
from sqlalchemy.orm import Session, relationship
import itertools

class Base(object):
    """Base class which provides automated table name
    and surrogate primary key column.

    """
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()
    id = Column(Integer, primary_key=True)
Base = declarative_base(cls=Base)

class Address(Base):
    """The Address class.   

    This represents all address records in a 
    single table.

    """
    street = Column(String)
    city = Column(String)
    zip = Column(String)

    @property
    def all_owners(self):
        return list(
            itertools.chain(
            *[
                getattr(self, attr)
                for attr in [a for a in dir(self) if a.endswith("_parents")]
            ]
        ))

    def __repr__(self):
        return "%s(street=%r, city=%r, zip=%r)" % \
            (self.__class__.__name__, self.street, 
            self.city, self.zip)

class HasAddresses(object):
    """HasAddresses mixin, creates a new address_association
    table for each parent.

    """
    @declared_attr
    def addresses(cls):
        address_association = Table(
            "%s_addresses" % cls.__tablename__,
            cls.metadata,
            Column("address_id", ForeignKey("address.id"), 
                                primary_key=True),
            Column("%s_id" % cls.__tablename__, 
                                ForeignKey("%s.id" % cls.__tablename__), 
                                primary_key=True),
        )
        return relationship(Address, secondary=address_association, 
                    backref="%s_parents" % cls.__name__.lower())

class Customer(HasAddresses, Base):
    name = Column(String)

class Supplier(HasAddresses, Base):
    company_name = Column(String)

engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)

session = Session(engine)

a1 = Address(
            street='123 anywhere street',
            city="New York",
            zip="10110")
a2 = Address(
            street='40 main street',
            city="San Francisco",
            zip="95732")

session.add_all([
    Customer(
        name='customer 1', 
        addresses=[a1, a2]
    ),
    Supplier(
        company_name="Ace Hammers",
        addresses=[a1]
    ),
])

session.commit()

for customer in session.query(Customer):
    for address in customer.addresses:
        print address.all_owners

是的,我有一个怀疑,表每单位协会是一个更好的起点。非常感谢你。