15

db.Modelからへの移行中ですndb.Model。この移行を完了する前に解決しなければならない唯一の問題は、Model.is_saved方法がないことです。アプリケーションで、シャードさdb.Model.is_savedれたカウンターをput/deleteで更新する必要があるかどうかを判断したり、エンティティの作成時に競合するキーをチェックしたりしました。

ドキュメントには、メソッドndb.Modelに相当するものはないと書かれていis_savedます。get_or_insertの代わりに を使用して、いくつかのユース ケースを再実装できますis_saved。しかし、それらすべてではありません。

汚いハックとして、_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
4

3 に答える 3

12

NDB で同じ種類の状態を取得するには、post-get-hook と post-put-hook を組み合わせてフラグを設定する必要があります。これが実際の例です:

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を参照してください。

于 2012-08-23T16:20:45.103 に答える
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

データストアに保持されることを保証することはできません。グーグルでそれについて何も見つかりませんでした:)

一方で、ndb.Modelインスタンスにキーがあるかどうかを確認することは、新しいインスタンスがデータストアに送信される前にキーを取得しているように見えるため、おそらく機能しません。ソースコードを見て、ndb.Modelクラスのインスタンスを作成するとどうなるかを確認できます。

于 2012-08-23T07:26:05.957 に答える
1

モデルのインスタンスを作成するときにキーを指定しない場合は、次の実装を使用してis_saved()、オブジェクトがデータストアに書き込まれたことがあるか、少なくとも 1 回も書き込まれていないかどうかを確認できます。(google.appengine.ext.db から google.appengine.ext.ndb に移行する場合に適しています)

@fredrik の例を使用すると、

class Article(ndb.Model):
    title = ndb.StringProperty()
    
    def is_saved(self):
        if self.key:
            return True
        return False

PS - これが google.cloud.ndb で機能するかどうかはわかりません

于 2021-06-11T11:05:34.443 に答える