我有两个表,tablet
和correspondent
:
class Correspondent(db.Model, GlyphMixin):
# PK column and tablename etc. come from the mixin
name = db.Column(db.String(100), nullable=False, unique=True)
# association proxy
tablets = association_proxy('correspondent_tablets', 'tablet')
def __init__(self, name, tablets=None):
self.name = name
if tablets:
self.tablets = tablets
class Tablet(db.Model, GlyphMixin):
# PK column and tablename etc. come from the mixin
area = db.Column(db.String(100), nullable=False, unique=True)
# association proxy
correspondents = association_proxy('tablet_correspondents', 'correspondent')
def __init__(self, area, correspondents=None):
self.area = area
if correspondents:
self.correspondents = correspondents
class Tablet_Correspondent(db.Model):
__tablename__ = "tablet_correspondent"
tablet_id = db.Column("tablet_id",
db.Integer(), db.ForeignKey("tablet.id"), primary_key=True)
correspondent_id = db.Column("correspondent_id",
db.Integer(), db.ForeignKey("correspondent.id"), primary_key=True)
# relations
tablet = db.relationship(
"Tablet",
backref="tablet_correspondents",
cascade="all, delete-orphan",
single_parent=True)
correspondent = db.relationship(
"Correspondent",
backref="correspondent_tablets",
cascade="all, delete-orphan",
single_parent=True)
def __init__(self, tablet=None, correspondent=None):
self.tablet = tablet
self.correspondent = correspondent
我可以向tablet
和correspondent
添加记录,例如正如您所料,Tablet.query.first().correspondents
只返回一个空列表。如果我使用现有平板电脑和通讯ID手动在我的tablet_correspondent
表格中插入一行,则会再次按照您的预期填充列表。
但是,如果我尝试
cor = Correspondent.query.first()
tab = Tablet.query.first()
tab.correspondents.append(cor)
我明白了:
KeyError: 'tablet_correspondents'
我很确定我在这里遗漏了一些相当基本的东西。
答案 0 :(得分:12)
代码中的问题位于.__init__
方法中。如果您要debug-watch/print()
参数,您会注意到参数tablet
实际上是Correspondent
的一个实例:
class Tablet_Correspondent(db.Model):
def __init__(self, tablet=None, correspondent=None):
print "in __init__: ", tablet, correspondent
self.tablet = tablet
self.correspondent = correspondent
这样做的原因是SA创建新值的方式。来自文档Creation of New Values:
列表
append()
事件(或设置add()
,字典__setitem__()
或 标量赋值事件)由关联代理拦截它 使用它实例化“中间”对象的新实例 构造函数,作为给定值的单个参数传递。
在您拨打tab.correspondents.append(cor)
的情况下,使用单个参数Tablet_Correspondent.__init__
调用cor
。
解决方案?如果您只将Correspondents
添加到Tablet
,则只需切换__init__
中的参数即可。实际上,完全删除第二个参数
但是,如果您还将使用cor.tablets.append(tab)
,则需要明确使用creator
association_proxy
参数,如上文链接的文档中所述:
class Tablet(db.Model, GlyphMixin):
# ...
correspondents = association_proxy('tablet_correspondents', 'correspondent', creator=lambda cor: Tablet_Correspondent(correspondent=cor))
class Correspondent(db.Model, GlyphMixin):
# ...
tablets = association_proxy('correspondent_tablets', 'tablet', creator=lambda tab: Tablet_Correspondent(tablet=tab))
答案 1 :(得分:1)
如van所说,问题仍然存在于Association Object的__init__
方法中。
事实上,如果Tablet或Correspondent类没有定义__init__
方法或者没有传递任何参数,则解决方案不起作用(不需要参数)。
我找到了另一种解决方案。很容易检测哪个类必须被代理,因此可以将其分配到正确的字段(并且仍然可以添加更多关联):
class Tablet_Correspondent(db.Model):
# ...
def __init__(self, proxied=None):
if type(proxied) is Tablet:
self.tablet = proxied
elif type(proxied) is Correspondent:
self.correspondent = proxied