SQLAlchemy关联代理和列表

时间:2016-12-31 00:10:44

标签: python sqlalchemy

我正在尝试找出如何在多对多关系中获取关联代理以默认返回空列表。

所以基于以下示例: https://raw.githubusercontent.com/zzzeek/sqlalchemy/master/examples/generic_associations/discriminator_on_association.py

我们有:

from sqlalchemy.ext.declarative import as_declarative, declared_attr
from sqlalchemy import create_engine, Integer, Column, \
                    String, ForeignKey
from sqlalchemy.orm import Session, relationship, backref
from sqlalchemy.ext.associationproxy import association_proxy

@as_declarative()
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)

class AddressAssociation(Base):
    """Associates a collection of Address objects
    with a particular parent.

    """
    __tablename__ = "address_association"

    discriminator = Column(String)
    """Refers to the type of parent."""

    __mapper_args__ = {"polymorphic_on": discriminator}

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

    This represents all address records in a
    single table.

    """
    association_id = Column(Integer, ForeignKey("address_association.id"))
    street = Column(String)
    city = Column(String)
    zip = Column(String)
    association = relationship("AddressAssociation", backref="addresses")

    parent = association_proxy("association", "parent")

    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 relationship to
    the address_association table for each parent.

    """
    @declared_attr
    def address_association_id(cls):
        return Column(Integer, ForeignKey("address_association.id"))

    @declared_attr
    def address_association(cls):
        name = cls.__name__
        discriminator = name.lower()

        assoc_cls = type(
                        "%sAddressAssociation" % name,
                        (AddressAssociation, ),
                        dict(
                            __tablename__=None,
                            __mapper_args__={
                                "polymorphic_identity": discriminator
                            }
                        )
                    )

        cls.addresses = association_proxy(
                    "address_association", "addresses",
                    creator=lambda addresses: assoc_cls(addresses=addresses)
                )
        return relationship(assoc_cls,
                    backref=backref("parent", uselist=False))


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)

但是,如果我试着查看客户的地址,我会得到None而不是[]我期望的那样:

(Pdb) foo = Customer()
(Pdb) foo.addresses
(Pdb)  
(Pdb) type(foo.addresses)
<type 'NoneType'>

这意味着我不能简单地迭代foo.addresses而不先检查它None

我尝试在关联代理上设置uselist = True

        return relationship(assoc_cls,
                    uselist=True,
                    backref=backref("parent", uselist=False))

哪种方法有效,但构造函数失败了:

(Pdb) foo.addresses
[]
(Pdb) foo.addresses.append(Address())
*** TypeError: Incompatible collection type: Address is not list-like
(Pdb) 

我尝试弄乱creator以使其构建一个列表,但随后导致各种副作用,包括嵌套列表:

    cls.addresses = association_proxy(
                "address_association", "addresses",
                creator=lambda addresses: assoc_cls(addresses=[addresses,])

任何想法都是最好的解决方法吗?

-Matt

0 个答案:

没有答案