我正在尝试找出如何在多对多关系中获取关联代理以默认返回空列表。
我们有:
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