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.

  • NameError: глобальное имя «execfile» не определено, пытаясь запустить приложение в Google App Engine Launcher
  • Смешивание холста HTML5 и Python
  • скачать изображения с помощью Google Custom Search api
  • GAE: Невозможно использовать API-интерфейс стороннего сервера Google (проблема с whitelisting)
  • Доступ к Google Диску из приложения Python для приложения Google App Engine
  • Как настроить app.yaml для поддержки URL-адресов, например / user / <user-id>?
  • Ошибка синтаксического анализа запроса предка
  • Индикатор выполнения в Google App Engine
  • Как писать необработанные байты в хранилище облачных хранилищ Google с помощью API-интерфейса GAE Python
  • Как получить последние данные в GAE Python NDB
  • Можно ли определить с помощью NDB, если модель устойчива в хранилище данных или нет?
  •  
    Interesting Posts for Van-Lav

    Различия между isinstance () и type () в python

    поток файлов python ftp или многопроцессорный

    Использовать Python для записи вывода CSV в STDOUT

    Альтернатива Squish для Qt

    Как я могу разделить строку на токены?

    Django- Connection отказался при использовании smtp

    Получать ответы от Gmail с помощью smtplib – Python

    Django: Уведомления JSON с использованием Redis PubSub, Node.js и Socket.io

    Искусственная жизнь с нейронными сетями

    Преобразование Python-String в Bytes. Двойная проблема BackSlash

    Использование Python для декодирования изображений стеганографии (примеры изображений в Википедии)

    Django celery получает статус задачи с помощью Ajax

    В Pandas как преобразовать строку строк даты в объекты datetime и поместить их в DataFrame?

    Использование «из __future__ import division» в моей программе, но оно не загружено моей программой

    Как организовать проект python, который содержит несколько пакетов, чтобы каждый файл в пакете можно было запускать отдельно?

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