classFriend(ndb.Model):name=ndb.StringProperty()def_pre_put_hook(self):_notify('Gee wiz I have a new friend!')@classmethoddef_post_delete_hook(cls,key,future):_notify('I have found occasion to rethink our friendship.')
...
f=Friend()f.name='Carole King'f.put()# _pre_put_hook is calledfut=f.key.delete_async()# _post_delete_hook not yet calledfut.get_result()# _post_delete_hook is called
非同期 API でポストフックを使用する場合、check_result()、get_result() を呼び出すか、(タスクレット内で)非同期メソッドの future を生成することで、フックがトリガーされます。ポストフックは、RPC が成功したかどうかを検査しません。失敗した場合でも、フックは実行されます。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["わかりにくい","hardToUnderstand","thumb-down"],["情報またはサンプルコードが不正確","incorrectInformationOrSampleCode","thumb-down"],["必要な情報 / サンプルがない","missingTheInformationSamplesINeed","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-09-04 UTC。"],[[["\u003cp\u003eThis page outlines the use of legacy bundled services and APIs within the App Engine standard environment's first-generation runtimes, with a note on migration options for Python 3 runtimes.\u003c/p\u003e\n"],["\u003cp\u003eEntities can be structured by creating a model class that defines specific properties, offering a structured approach to data storage.\u003c/p\u003e\n"],["\u003cp\u003eThe Expando model class offers a flexible alternative, allowing attributes to be added dynamically without predefined properties, with added options to control indexing.\u003c/p\u003e\n"],["\u003cp\u003eModel hooks enable the execution of custom code before or after specific operations like \u003ccode\u003eget()\u003c/code\u003e, \u003ccode\u003eput()\u003c/code\u003e, and \u003ccode\u003edelete()\u003c/code\u003e, and may be used for tasks such as query caching or auditing.\u003c/p\u003e\n"],["\u003cp\u003ePre-hooks allow for the prevention of a request by raising an exception, while post-hooks are called regardless of the RPC's success and include a Future object to retrieve the result of the action.\u003c/p\u003e\n"]]],[],null,["# Creating Entity Models\n\n| This page describes how to use the legacy bundled services and APIs. This API can only run in first-generation runtimes in the App Engine standard environment. If you are updating to the App Engine Python 3 runtime, refer to the [migration guide](/appengine/migration-center/standard/migrate-to-second-gen/python-differences) to learn about your migration options for legacy bundled services.\n\nYou need to create a model class for your entity. You can do this in two ways:\n\n- Create a model class that defines entity properties.\n- Create an expando model class that does not define entities in advance.\n\nThis document describes how to create each of these types of model classes.\nIt also describes how to create a model hook, so that your\napplication can run some code before or after some type of operations, for\nexample, before each `get()`.\n\nCreating a model class with properties\n--------------------------------------\n\nBefore creating an entity, you must create a model class that defines one or\nmore entity properties. For example: \n\n from google.appengine.ext import ndb\n\n`...` \n\n class Account(ndb.Model):\n username = ndb.StringProperty()\n userid = ndb.IntegerProperty()\n email = ndb.StringProperty()\n\nwhere you want each Account entity to have properties for user name, user ID,\nand email.\n\nFor a full list of property types, see the [Entity Property Reference](/appengine/docs/legacy/standard/python/ndb/entity-property-reference).\n\nCreating an Expando model class\n-------------------------------\n\nYou don't have to use a model class that defines properties in advance.\nA special model subclass called `Expando` changes the behavior of\nits entities so that any attribute assigned is saved to the data store. Note\nthat such attributes can't start with an underscore.\n\nHere is how to create an Expando model: \n\n class Mine(ndb.Expando):\n pass\n\n`...` \n\n e = Mine()\n e.foo = 1\n e.bar = 'blah'\n e.tags = ['exp', 'and', 'oh']\n e.put()\n\nThis writes an entity to the data store with a\n`foo` property with integer value `1`,\na `bar` property with string value `'blah'`,\nand a repeated `tag` property with string\nvalues `'exp'`, `'and'`, and `'oh'`.\nThe properties are indexed, and you can inspect them using the\nentity's `_properties` attribute: \n\n return e._properties\n # {\n # 'foo': GenericProperty('foo'),\n # 'bar': GenericProperty('bar'),\n # 'tags': GenericProperty('tags', repeated=True)\n # }\n\nAn `Expando` created by getting a value from\nthe data store has properties for all property values that were saved\nin the data store.\n\nAn application can add predefined properties to an\n`Expando` subclass: \n\n class FlexEmployee(ndb.Expando):\n name = ndb.StringProperty()\n age = ndb.IntegerProperty()\n\n`...` \n\n employee = FlexEmployee(name='Sandy', location='SF')\n\nThis gives `employee` a `name` attribute with value `'Sandy'`,\nan `age` attribute with value `None`,\nand a dynamic attribute `location` with value `'SF'`.\n\nTo create an `Expando` subclass whose properties are unindexed,\nset `_default_indexed = False` in the subclass definition: \n\n class Specialized(ndb.Expando):\n _default_indexed = False\n\n`...` \n\n e = Specialized(foo='a', bar=['b'])\n return e._properties\n # {\n # 'foo': GenericProperty('foo', indexed=False),\n # 'bar': GenericProperty('bar', indexed=False, repeated=True)\n # }\n\nYou can also set `_default_indexed` on an `Expando` entity.\nIn this case it will affect all properties assigned *after* it was set.\n\nAnother useful technique is querying an `Expando` kind for a dynamic property. A\nquery like the following \n\n FlexEmployee.query(FlexEmployee.location == 'SF')\n\nwon't work, because the class doesn't have a property object for the location\nproperty. Instead, use `GenericProperty`, the class `Expando` uses for dynamic\nproperties: \n\n FlexEmployee.query(ndb.GenericProperty('location') == 'SF')\n\nUsing Model Hooks\n-----------------\n\nNDB offers a lightweight hooking mechanism. By defining a hook, an application\ncan run some code before or after some type of operations; for example, a `Model`\nmight run some function before every `get()`.\n\nA hook function runs when using the synchronous, asynchronous and multi versions\nof the appropriate method. For example, a \"pre-get\" hook would apply to all of\n`get()`, `get_async()`, and `get_multi()`. There are pre-RPC and post-RPC versions\nof each hook.\n\nHooks can be useful for the following:\n\n- query caching\n- auditing Cloud Datastore activity per-user\n- mimicking database triggers\n\nThe following example shows how to define hook functions: \n\n from google.appengine.ext import ndb\n\n`...` \n\n class Friend(ndb.Model):\n name = ndb.StringProperty()\n\n def _pre_put_hook(self):\n _notify('Gee wiz I have a new friend!')\n\n @classmethod\n def _post_delete_hook(cls, key, future):\n _notify('I have found occasion to rethink our friendship.')\n\n`...` \n\n f = Friend()\n f.name = 'Carole King'\n f.put() # _pre_put_hook is called\n fut = f.key.delete_async() # _post_delete_hook not yet called\n fut.get_result() # _post_delete_hook is called\n\nIf you use post-hooks with asynchronous APIs, the hooks are triggered by calling\n`check_result()`, `get_result()` or yielding (inside a tasklet) an async\nmethod's future.\nPost hooks do not check whether the RPC was successful;\nthe hook runs regardless of failure.\n\nAll post- hooks have a [Future](/appengine/docs/legacy/standard/python/ndb/async)\nargument at the end of the call signature. This `Future` object\nholds the result of the action. You can call `get_result()`\non this `Future` to retrieve the result; you can be sure that `get_result()`\nwon't block, since the `Future` is complete by the time the hook is called.\n\nRaising an exception during a pre-hook prevents the request from taking place.\nAlthough hooks are triggered inside `\u003cvar\u003e*\u003c/var\u003e_async` methods, you cannot\npre-empt an RPC by raising `tasklets.Return` in a pre-RPC hook.\n\nWhat's next\n-----------\n\n- [Learn more about the NDB Model class](/appengine/docs/legacy/standard/python/ndb/modelclass).\n- [Explore the entity property reference documentation](/appengine/docs/legacy/standard/python/ndb/entity-property-reference)."]]