更新:
对于有此问题的任何人,使用最新的SQLAlchemy,此行为已得到修复.
原始问题:
我遇到了使关联代理正确更新的问题.
使用此处的示例模型:http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/associationproxy.html#simplifying-association-objects
但是使用以下行更改UserKeyword:
keyword = relationship("Keyword", backref=backref("user_keywords", cascade="all, delete-orphan"))
Run Code Online (Sandbox Code Playgroud)
并将其添加到关键字:
users = association_proxy('user_keywords', 'user')
Run Code Online (Sandbox Code Playgroud)
因此,关键字实例具有用户列表.
以下按预期工作:
>>> rory = User("rory")
>>> session.add(rory)
>>> chicken = Keyword('chicken')
>>> session.add(chicken)
>>> rory.keywords.append(chicken)
>>> chicken.users
[<__main__.User object at 0x1f1c0d0>]
>>> chicken.user_keywords
[<__main__.UserKeyword object at 0x1f1c450>]
Run Code Online (Sandbox Code Playgroud)
但删除做奇怪的事情.从关联代理列表中删除如下:
>>> rory.keywords.remove(chicken)
Run Code Online (Sandbox Code Playgroud)
SA尝试将其中一个外键列设置为null时,会导致完整性错误.
这样做:
>>> rory.user_keywords.remove(rory.user_keywords[0])
Run Code Online (Sandbox Code Playgroud)
结果如下:
>>> chicken.users
[None]
Run Code Online (Sandbox Code Playgroud)
我错过了一些显而易见的事情吗?
UserKeyword要求它与a Keyword和同时关联User以便持久化.当你将其与关联User和Keyword,但后来从删除User.user_keywords集合,它仍然与关联Keyword.
>>> rory.keywords.remove(chicken)
# empty as we expect
>>> rory.user_keywords
[]
# but the other side, still populated. UserKeyword
# has no User, but still has Keyword
>>> chicken.user_keywords
[<__main__.UserKeyword object at 0x101748d10>]
# but the User on that UserKeyword is None
>>> chicken.user_keywords[0].user is None
True
# hence accessing the "association" gives us None
# as well
>>> chicken.users
[None]
Run Code Online (Sandbox Code Playgroud)
所以,如果我们现在要刷新(),你已经UserKeyword准备好了一个对象,但它没有User,所以你得到了NULL错误.在INSERT时,该对象不被视为"孤儿",除非它与任何Keyword.user_keywords 或 User.user_keywords集合无关.只有当你说del chicken.user_keywords[0]或等效时,才会看到没有生成INSERT并且UserKeyword忘记了该对象.
如果您要在将对象从"rory"中删除之前将对象刷新到数据库,那么事情会发生变化.在UserKeyword现在是持久的,而当你从"rory.keywords","删除孤儿"事件触发关闭其删除"鸡" 不删除UserKeyword,即使它仍然是有关联的Keyword对象:
rory.keywords.append(chicken)
session.flush()
rory.keywords.remove(chicken)
session.flush()
Run Code Online (Sandbox Code Playgroud)
你看到SQL了:
INSERT INTO "user" (name) VALUES (%(name)s) RETURNING "user".id
{'name': 'rory'}
INSERT INTO keyword (keyword) VALUES (%(keyword)s) RETURNING keyword.id
{'keyword': 'chicken'}
INSERT INTO user_keyword (user_id, keyword_id, special_key) VALUES (%(user_id)s, %(keyword_id)s, %(special_key)s)
{'keyword_id': 1, 'special_key': None, 'user_id': 1}
DELETE FROM user_keyword WHERE user_keyword.user_id = %(user_id)s AND user_keyword.keyword_id = %(keyword_id)s
{'keyword_id': 1, 'user_id': 1}
Run Code Online (Sandbox Code Playgroud)
现在一个理智的人会问,"这不是不一致吗?" 而目前我会说,"绝对".我需要查看测试用例以了解这种行为差异的基本原理,我已经在代码中确定了为什么它会以这种方式出现,而且我很确定这种"孤儿"如何被考虑的区别"待定"与"持久"对象是故意的,但在这种特定的排列中显然会产生奇怪的结果.如果我能找到一个可行的话,我可能会在0.8中做出改变.
编辑:http://www.sqlalchemy.org/trac/ticket/2655总结了我将要考虑的问题.特别是对这种行为进行了测试,需要追溯到它的起源.
| 归档时间: |
|
| 查看次数: |
1967 次 |
| 最近记录: |