2012-08-23 8 views
13

私はdb.Modelからndb.Modelに移行中です。この移行を完了する前に解決しなければならない唯一の問題は、Model.is_savedメソッドがないことです。私は、ドキュメントがndb.Modelis_saved方法には相当していないことを言うなどのエンティティを作成する上で競合のキーをチェックするために、シャードのカウンタがput/deleteに更新されなければならないかどうかを判断するために自分のアプリケーションにモデルがデータストア内で永続的であるかどうかをNDBで判断できますか?

db.Model.is_savedを使用しています。 is_savedではなく、get_or_insertのユースケースを再実装できます。しかし、それらのすべてではありません。

汚れたハックとして、私はコンストラクタを呼び出して作成したすべてのインスタンスに対して_in_memory_instanceのようなフラグを設定できます。しかし、それは私の問題を解決しません。私はまだ少なくとも毎月put()呼び出しの後でこのフラグを更新する必要があります。

質問:データストアにモデルが永続的であるかどうかを判断する良い方法はありますか?

編集1:言及を忘れてしまった:すべてのエンティティが鍵を持っているので、Model._has_complete_key()が私のために働いていないことを確認してください。

編集2:このディスカッションの後にhttps://groups.google.com/d/topic/google-appengine/Tm8NDWIvc70/discussionそれは私の問題を解決する唯一の方法と思われる_post_get_hook/_post_put_hookを使用することです。なぜ私はそのような些細なことが公式APIに含まれていないのだろうと思う。

編集3:すべてのモデルで次の基本クラスになりました。今私は(ほぼ)そのまま私のコードベースを残すことができます:

class BaseModel(ndb.Model): 

    @classmethod 
    def _post_get_hook(cls, key, future): 
     self = future.get_result() 
     if self: 
      self._is_saved = bool(key) 

    def _post_put_hook(self, future): 
     self._is_saved = future.state == future.FINISHING 

    def is_saved(self): 
     if self._has_complete_key(): 
      return getattr(self, "_is_saved", False) 
     return False 
+0

オブジェクトに実際にキー/ IDがあるかどうかを確認できますか? (おそらくtry/except節で)。 NDBモデルクラスに精通していませんが、db.Modelがエラーを発生させることを思い出します(またはNone?)保存する前にモデルインスタンスのid/keyを取得しようとすると(またはおそらく 'None'を返します)。データストアのヒットで終わるとは思わないでください。それがうまくいけば、 'def is_saved(self):return self.key()is None'のようなプロパティを書くことができます(あるいは、例外が発生した場合にTrueを返すtry/except節で行います。 )。 –

+0

キーを作成している場合、キーを確認することはできません。 1つの可能性のある代替案(ただし不十分かもしれない)には、creation_dateフラグ(auto_now_add = Trueに設定)があります。ドキュメントから "エンティティが書き込まれるまで自動値は生成されません;つまり、これらのオプションは動的なデフォルトを提供しません。"しかし、書き込みに失敗すると、その値が設定されます。書き込みが失敗したことを知っておくべきですが、 –

+1

は_post_put_hookを使用して、保存されたことを示すフラグを設定します。 –

答えて

11

NDBで同じ種類の状態を取得するには、フラグを設定するためにポストゲットフックとポストプットフックの組み合わせが必要です。ここで働いて 例です:

class Employee(ndb.Model): 
    <properties here> 

    saved = False # class variable provides default value 

    @classmethod 
    def _post_get_hook(cls, key, future): 
    obj = future.get_result() 
    if obj is not None: 
     # test needed because post_get_hook is called even if get() fails! 
     obj.saved = True 

    def _post_put_hook(self, future): 
    self.saved = True 

は、将来の状態をチェックする必要はありません - のいずれか フックが呼び出されたときに、未来は常に結果を持っています。これは、実際には フックが将来のコールバックであるためです。しかし、その結果がNoneならば のチェックが必要です!

PS:トランザクション内では、put()コールが返されるとすぐにフックが呼び出されます。取引の成功または失敗はそれらに影響を与えません。コミットが成功した後にフックを実行する方法については、https://developers.google.com/appengine/docs/python/ndb/contextclass#Context_call_on_commitを参照してください。

+5

[here](https://code.google.com/p/appengine-ndb-experiment/issues/detail?id=211)で説明したように、_post_get_hookが存在しないため、トラフクエリー/ gqlを取得したエンティティでは機能しませんそれらに対して呼び出され、クエリには(まだ)同等のコールバックはありません。 –

2

を@Tim Hoffmans考えに基づき、あなたがそのようなポストフックすることができます:

class Article(ndb.Model): 
    title = ndb.StringProperty() 

    is_saved = False 

    def _post_put_hook(self, f): 
     if f.state == f.FINISHING: 
      self.is_saved = True 
     else: 
      self.is_saved = False 


article = Article() 
print article.is_saved ## False 
article.put() 
print article.is_saved ## True 

私はそれがに固執していますことを保証することはできませんデータストア。 Googleでそれについて何も見つかりませんでした。

ndb.Modelインスタンスにキーがあるかどうかを調べるには、新しいインスタンスが送信される前にKeyを取得しているようであるためデータストアに転送します。 source codeを見ると、ndb.Modelクラスのインスタンスを作成したときの動作を確認できます。

+1

回避策として使用するには十分に近いです。だから+1に投票する。より良い解決策が現れないなら、数日後にあなたの答えを受け入れるでしょう。 – Sergey

+0

私がこのアプローチで現在目指している唯一の欠点は、エンティティが作成されるのではなく取り出された場合、 'is_saved'が' False'になることです。これは 'is_saved()'の 'db.Model'動作には対応しません。完全にするには、is_savedをTrueに設定する '_post_get_hook'メソッドを追加したいと思うかもしれません。 –

関連する問題