API приложений (Python) Datastore Precall API

Задний план

Итак, допустим, я создаю приложение для GAE, и я хочу использовать API Hooks .

БОЛЬШОЙ РЕДАКТИРОВАНИЕ : В исходной версии этого вопроса я описал свой вариант использования, но некоторые люди правильно указали, что он не подходит для API-крючков. Предоставляется! Подумайте, мне помогли. Но теперь моя проблема академическая: я до сих пор не знаю, как использовать крючки на практике, и я бы хотел. Я переписал свой вопрос, чтобы сделать его более универсальным.


Код

Поэтому я делаю такую ​​модель:

class Model(db.Model): user = db.UserProperty(required=True) def pre_put(self): # Sets a value, raises an exception, whatever. Use your imagination 

И затем я создаю db_hooks.py:

 from google.appengine.api import apiproxy_stub_map def patch_appengine(): def hook(service, call, request, response): assert service == 'datastore_v3' if call == 'Put': for entity in request.entity_list(): entity.pre_put() apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('preput', hook, 'datastore_v3') 

Будучи TDD-addled, я делаю все это с помощью GAEUnit , поэтому в gaeunit.py, чуть выше основного метода, добавляю:

 import db_hooks db_hooks.patch_appengine() 

И затем я пишу тест, который создает экземпляр и помещает модель.


Вопрос

Хотя patch_appengine() определенно называется, хук никогда не бывает. Что мне не хватает? Как я могу заставить функцию pre_put получить вызов?

3 Solutions collect form web for “API приложений (Python) Datastore Precall API”

Крюки немного низки для поставленной задачи. Вероятно, вам нужен собственный класс свойств. DerivedProperty, от aetycoon , это всего лишь билет.

Имейте в виду, однако, что поле «никнейм» объекта пользователя, вероятно, не то, что вы хотите – в документах , это просто пользовательская часть поля электронной почты, если они используют учетную запись gmail, иначе это полный адрес электронной почты адрес. Вероятно, вы захотите, чтобы пользователи установили свои собственные псевдонимы.

Проблема здесь в том, что в контексте функции hook() entity не является экземпляром db.Model, как вы ожидаете.

В этом контексте entity является классом буфера протокола, смехотворно называемым entity ( entity_pb ). Подумайте об этом как о представлении JSON вашего реального объекта, все данные есть, и вы можете создать из него новый экземпляр, но нет ссылки на ваш экземпляр-резидентный экземпляр, ожидающий его обратного вызова.

Обезболивание всех различных методов put/delete – лучший способ настроить обратные вызовы на уровне модели, насколько я знаю …

Поскольку, похоже, не так много ресурсов о том, как сделать это безопасно с новыми вызовами async, вот BaseModel, который реализует before_put, after_put, before_delete & after_delete hooks:

 class HookedModel(db.Model): def before_put(self): logging.error("before put") def after_put(self): logging.error("after put") def before_delete(self): logging.error("before delete") def after_delete(self): logging.error("after delete") def put(self): return self.put_async().get_result() def delete(self): return self.delete_async().get_result() def put_async(self): return db.put_async(self) def delete_async(self): return db.delete_async(self) 

Наследуйте свои классы моделей из HookedModel и переопределите методы before_xxx, after_xxx по мере необходимости.

Разместите следующий код где-нибудь, который будет загружен в глобальном масштабе в вашем приложении (например, main.py если вы используете довольно стандартно выглядящий макет). Это та часть, которая называет наши крючки:

 def normalize_entities(entities): if not isinstance(entities, (list, tuple)): entities = (entities,) return [e for e in entities if hasattr(e, 'before_put')] # monkeypatch put_async to call entity.before_put db_put_async = db.put_async def db_put_async_hooked(entities, **kwargs): ents = normalize_entities(entities) for entity in ents: entity.before_put() a = db_put_async(entities, **kwargs) get_result = a.get_result def get_result_with_callback(): for entity in ents: entity.after_put() return get_result() a.get_result = get_result_with_callback return a db.put_async = db_put_async_hooked # monkeypatch delete_async to call entity.before_delete db_delete_async = db.delete_async def db_delete_async_hooked(entities, **kwargs): ents = normalize_entities(entities) for entity in ents: entity.before_delete() a = db_delete_async(entities, **kwargs) get_result = a.get_result def get_result_with_callback(): for entity in ents: entity.after_delete() return get_result() a.get_result = get_result_with_callback return a db.delete_async = db_delete_async_hooked 

Вы можете сохранять или уничтожать свои экземпляры с помощью model.put () или любых методов db.put (), db.put_async () и т. Д. И получать желаемый эффект.

† хотел бы знать, есть ли еще лучшее решение !?

Я не думаю, что Крюки действительно собираются решить эту проблему. Крюки будут запускаться только в контексте вашего приложения AppEngine, но пользователь может изменить свой ник вне вашего приложения, используя настройки учетной записи Google. Если они это сделают, это не вызовет каких-либо логических реализаций в ваших крючках.

Я думаю, что реальное решение вашей проблемы заключается в том, что ваше приложение управляет своим собственным псевдонимом, который не зависит от того, который был открыт субъектом Users.

  • Насколько быстрыми являются App Engine db.get (ключи) и A.all (keys_only = True) .filter ('b =', b) .fetch (1000)?
  • Почему я получаю сообщение «Слишком много индексированных свойств для сущности» только для 18 элементов в списке? (Python)
  • Функция Pubnub Presence в Python (GAE)
  • GAE: KindError при получении объектов через ListProperty
  • Справочный вопрос в приложении Engine db.model
  • API GoogleMaps -address для координат (широта, долгота)
  • Модельный шаблон дизайна для Google App Engine
  • Google App Engine: как отключить кеш на «статических» файлах или сделать кеш-смарт
  •  
    Interesting Posts for Van-Lav

    Python: как импортировать все методы и атрибуты из модуля динамически

    google.protobuf установлен, но модуль не найден

    Как можно генерировать индексы numpy.ufunc.reduceat из объекта среза Python

    Python splitext

    невидимые водяные знаки в изображениях

    Нужен общий xpath для следующего html-кода

    Как найти фиксированное число (почти) фиксированных прямоугольников пропорций с opencv?

    Как я могу получить те же «специальные» решения для недоопределенных линейных систем, которые возвращает оператор Matlab `A \ b` (mldivide) с помощью numpy / scipy?

    Последовательное получение от Arduino до малины Pi с PySerial останавливается через некоторое время

    Преобразование строки в int слишком медленно

    Понимание синтаксиса синтаксиса matplotlib

    Raw_Input () не определен

    В чем разница между функциями json.load () и json.loads () в Python?

    разделять элементы списка в python

    Преобразование Python из двоичной строки в шестнадцатеричную

    Python - лучший язык программирования в мире.