2013-01-23 10 views
8

アップデート:この動作が修正されましたvery latest SQLAlchemyで、この問題を持つ人のため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")) 

とキーワードにこれを追加することを:

users = association_proxy('user_keywords', 'user') 

だから、キーワードインスタンスがのリストがあり、ここで例のモデルを使用して

ユーザー。

予想通り、次の作品:

>>> 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>] 

しかし、削除は奇妙なことを行います。そのような関連プロキシリストからの削除:SAはnullに外部キー列の1つを設定しようとして

>>> rory.keywords.remove(chicken) 

は、整合性エラーが発生します。私は何かを明らかに見逃している

>>> chicken.users 
[None] 

は私が持っていない。この中

>>> rory.user_keywords.remove(rory.user_keywords[0]) 

結果:

これをやって?

答えて

7

UserKeywordは、永続化するために同時にKeywordUserの両方に関連付けられる必要があります。 UserKeywordに関連付けてから、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] 

だから、あなたは行く準備ができUserKeywordオブジェクトを持っていますが、そのNULLのエラーが出るので、それは、それにはUserを持っていません。 INSERT時に、オブジェクトはKeyword.user_keywordsまたはUser.user_keywordsのコレクションに関連付けられていない限り、「孤児」とはみなされません。 del chicken.user_keywords[0]またはそれと同等の場合にのみ、INSERTは生成されず、UserKeywordオブジェクトは忘れてしまいます。

"rory"からオブジェクトを削除する前にオブジェクトをデータベースにフラッシュすると、物事が変わります。 UserKeywordは永続化され、「rory」から「chicken」を削除すると、キーワード」、 "それはまだKeywordオブジェクトに関連付けられているにもかかわらず、UserKeywordを削除しないoffの削除 - 孤児" のイベントが発生します:

rory.keywords.append(chicken) 

session.flush() 

rory.keywords.remove(chicken) 

session.flush() 

あなたが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} 

を私は、テストケースを調べて、この行動の違いがどういうものなのかを調べる必要があります。私は、このようにしてコードが特定された理由はわかりました。「孤児」の考え方の違い「保留中」のオブジェクトと「永続性の」オブジェクトの間の差は意図的ですが、この特定の順列では明らかに奇妙な結果が生じます。実現可能なものを見つけることができたら、これを0.8に変更するかもしれません。

編集:http://www.sqlalchemy.org/trac/ticket/2655は、私が考えなければならない問題を要約しています。この動作のテストが特にあり、その動作を元に戻す必要があります。

+0

ありがとうヒープzzzeek。 –