问题描述
我有两个表,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
表中,该列表将再次按照您的预期填充.
I can add records to tablet
and correspondent
, and doing e.g. Tablet.query.first().correspondents
simply returns an empty list, as you would expect. If I manually insert a row into my tablet_correspondent
table using existing tablet and correspondent IDs, the list is populated, again as you would expect.
但是,如果我尝试这样做
However, if I try to do
cor = Correspondent.query.first()
tab = Tablet.query.first()
tab.correspondents.append(cor)
我明白了:
KeyError: 'tablet_correspondents'
我很确定我在这里遗漏了一些相当基本的东西.
I'm pretty sure I'm leaving out something fairly elementary here.
推荐答案
您的代码的问题在 .__init__
方法中.如果你要debug-watch/print()
参数,你会注意到参数tablet
实际上是Correspondent
的一个实例:
The problem with your code is in the .__init__
method. If you are to debug-watch/print()
the parameters, you will notice that the parameter tablet
is actually an instance of 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 创造新价值的方式.来自文档创建新值一个>:
The reason for this is the way SA creates new values. From documentation Creation of New Values:
当一个列表append()
事件(或设置add()
,字典__setitem__()
,或标量赋值事件)被关联代理拦截,它使用其实例化中间"对象的新实例构造函数,将给定值作为单个参数传递.
在您调用 tab.correspondents.append(cor)
的情况下,Tablet_Correspondent.__init__
使用单个参数 cor
调用.
In your case when you call tab.correspondents.append(cor)
, the Tablet_Correspondent.__init__
is called with single argument cor
.
解决方案?如果你只是将Correspondents
添加到Tablet
,那么只需在__init__
中切换参数代码>.实际上,完全删除第二个参数.
但是,如果您还将使用 cor.tablets.append(tab)
,那么您需要明确地将 creator
参数用于 association_proxy
> 如上面链接的文档中所述:
Solution? If you will only be adding Correspondents
to the Tablet
, then just switch the parameters in the __init__
. In fact, remove the second parameter completely.
If, however, you will also be using cor.tablets.append(tab)
, then you need to explicitely use the creator
argument to the association_proxy
as explained in the documentation linked to above:
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))
这篇关于将对象添加到 SQLAlchemy 关联对象时出现 KeyError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!