Можно ли определить с помощью NDB, если модель устойчива в хранилище данных или нет?
Я перемещаюсь от 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.
Edit 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
Ответы
Ответ 1
Чтобы получить такое же состояние в 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
Нет необходимости проверять статус будущего - когда либо
крюк называется, будущее всегда имеет результат. Это связано с тем, что
hook на самом деле является обратным вызовом в будущем. Однако существует необходимость
проверьте, нет ли его результата None!
PS: внутри транзакции крючки вызываются, как только вызов put() возвращается; успех или неудача транзакции не влияют на них. См. https://developers.google.com/appengine/docs/python/ndb/contextclass#Context_call_on_commit для способа запуска крюка после успешной фиксации.
Ответ 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 имеет ключ, вероятно, не будет работать, поскольку новый экземпляр, похоже, получит ключ до его отправки в хранилище данных. Вы можете посмотреть исходный код, чтобы узнать, что происходит, когда вы создаете экземпляр класса ndb.Model.