Python 2 不再受社区支持。我们建议您将 Python 2 应用迁移到 Python 3

NDB Model 类

Model 类继承的类代表 Datastore 中所存储实体的结构。应用定义模型类,以指示其实体的结构,然后对这些模型类进行实例化,以创建实体。 所有模型类必须(直接或间接地)从 Model 继承。

此页面包含 API 参考文档。如需查看概览,请参阅 NDB 实体和键

简介

Model 继承的类描述 Datastore 实体。

所有模型类必须(直接或间接地)从 Model 继承。模型类定义中的直接赋值可用于声明模型的结构:

from google.appengine.ext import ndb

class Person(ndb.Model):
  name = ndb.StringProperty()
  age = ndb.IntegerProperty()

现在,我们可以创建 Person 实体,并将其写入数据存储区:

p = Person(name='Arthur Dent', age=42)
k = p.put()

put() 的返回值是一个,之后该键可用于检索同一实体:

p2 = k.get()
p2 == p  # Returns True

如需更新实体,只需更改其特性 (attribute) 并将其写回即可(注意,此操作不会更改键):

p2.name = 'Arthur Philip Dent'
p2.put()

我们还可以删除实体(通过使用键):

k.delete()

类主体中的属性定义会告知系统要在数据存储区中存储的字段的名称和类型、是否必须将这些字段编入索引、字段的默认值等。 存在许多不同的属性类型

种类通常与类名称(不包括模块名称或任何其他父级范围)相同。要替换种类(用于架构更改),请定义名为 _get_kind() 的类方法,如下所示:

  class MyModel(ndb.Model):
    @classmethod
    def _get_kind(cls):
      return 'AnotherKind'

应用不得定义两个具有相同种类的模型类,即使它们位于不同模块。应用的种类被视为全局“命名空间”。

Model 子类可定义大部分操作(get、put、delete、allocate_ids)的调用前和调用后钩子

构造函数

应用程序通常不会调用 Model(),但很可能调用继承自 Model 的类的构造函数。此操作会创建该模型的新实例,也称为实体。

新创建的实体不会自动写入数据存储区。 要使新创建的实体自动写入数据存储区,则必须通过明确调用 put() 将该实体写入 Datastore。

参数:

Model 子类支持以下关键字参数:

key
此模型的实例。如果使用 key 参数,则 idparent 必须是 None(默认值)。
id
此模型的键 ID。如果使用 id,则键必须为 None(默认值)。
parent
父模型的实例或顶级模型的 None。如果使用 parentkey 必须是 None
namespace
要用于此实体的命名空间,或者设置为 None(默认值)以使用当前命名空间。如果使用 namespacekey 必须是 None

应用还可以使用模型属性到关键字参数的映射。例如,以下示例可以正常工作:

class Person(ndb.Model):
  name = StringProperty()
  age = IntegerProperty()

p = Person(name='Arthur Dent', age=42)

您不能简单地定义名为“key”、“id”、“parent”或“namespace”的属性。 例如,如果您在构造函数或 populate() 调用中传递 key="foo",则它将设置实体的键,而不是名为“key”的属性。

注意:如果您在 Model 子类中重写该构造函数,请注意,在某些情况下,构造函数也会被隐式调用,因此请确保这些调用受支持。从数据存储区读取实体时,首先通过调用不含参数的构造函数来创建空实体,然后逐一设置键和属性 (property) 值。 当 get_or_insert()get_or_insert_async() 创建新实例时,它会将**constructor_args 传递给构造函数,然后设置该键。

类方法

allocate_ids(size=None, max=None, parent=None, **ctx_options)

为此模型类分配一系列键 ID。

参数

大小
要分配的 ID 数量。可以指定 sizemax,但不能同时指定这两者。
最大值
要分配的最大 ID。可以指定 sizemax,但不能同时指定这两者。
parent
将为其分配 ID 的父键。
**ctx_options
上下文选项

返回以 (start, end) 作为分配范围(含边界值)的元组。

应用程序无法在事务中调用 allocate_ids()

allocate_ids_async(size=None, max=None, parent=None, **ctx_options)

allocate_ids 的异步版本。

返回一个 Future 对象,该对象的结果以 (start, end) 作为分配范围(含边界值值)的元组。

get_by_id(id, parent=None, app=None, namespace=None, **ctx_options)
按 ID 返回实体。这实际上是 Key(cls, id).get() 的简写形式。

参数

id
字符串或整数键 ID。
parent
要获取的模型父键。
app (keyword arg)
如果应用 ID 未指定,则获取当前应用的数据。
namespace (keyword arg)
命名空间。如果未指定,则获取默认命名空间的数据。
**ctx_options
上下文选项

返回模型实例或 None(如未找到)。

get_by_id_async(id, parent=None, app=None, namespace=None, **ctx_options)
get_by_id 的异步版本。

返回其结果是模型实例的 Future 对象;;如果未找到,则返回 None

get_or_insert(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)
以事务方式检索现有实体或创建新实体。

参数

key_name
要检索或创建的键名(即,字符串键 ID)。
parent
父实体键(如有)。
应用
如果应用 ID 未指定,则获取当前应用的数据。
namespace
命名空间。如果未指定,则获取默认命名空间的数据。
context_options
上下文选项

如果指定键名的实例尚不存在,则此函数也会将关键字参数传递给模型类的构造函数。如果提供的 key_name 实例和父实例已存在,则系统将舍弃这些参数。

返回带有指定键名和父实体键的 Model 类的现有实例,或者返回刚创建的新实例。

此函数使用事务。如果调用此函数的代码已在事务中,则此函数会尝试重复使用现有事务。 如果此函数的实体组与现有事务不兼容,则会导致错误。

get_or_insert_async(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)

这是 get_or_insert 的异步版本。

它将返回 Future 对象,此对象的结果是带有指定键名和父实体键的 Model 类的现有实例,或者是刚创建的新实例。

query([filter1, filter2, ...,] ancestor=None, app=None, namespace=None, filters=None, orders=None, default_options=None, projection=None distinct=False group_by=None)

按照查询中的说明,为此类创建 Query 对象。

关键字参数 distinct 是 group_by = projection 的简写。所有其他关键字参数都传递给查询构造函数

如果位置参数是给定的,则用于设置初始过滤条件。

返回一个 Query 对象。

实例方法

populate(**constructor_options)

设置实体属性的值。实体关键字参数会自动识别属性名称,识别方式与构造函数相同。

put(**ctx_options)

将实体的数据写入数据存储区。返回实体的

参数

**ctx_options
上下文选项
put_async(**ctx_options)

将实体的数据异步写入数据存储区。返回一个 Future 对象。Future 对象的结果将是实体的

参数

**ctx_options
上下文选项
to_dict(include=all, exclude=None)

返回包含模型属性值的 dictStructuredPropertyLocalStructuredProperty 的属性值以递归方式转换为字典。

参数:

包括
要包括的可选属性列表。默认值:all。
排除
要排除的可选属性列表。如果 includeexclude 之间有重叠,则优先遵循 exclude

注意:如果属性值是可更改的对象(例如,代表重复属性的列表,或存储在 JsonProperty 中的字典或列表),除非该值已明确转换(例如,就 StructuredProperty 而言),否则在字典中返回的对象就是实体中所存储的相同对象。在这种情况下,更改字典后,实体也将更改,反之亦然。

实例数据

key
用于存储 Model 键的特殊属性。

钩子方法

应用的 Model 子类可以将这些方法中的一个或多个定义为操作前或操作后“钩子”方法。例如,要在每个“get”之前运行一些代码,请定义模型子类 _pre_get_hook() 方法。如需有关写入钩子函数的建议,请参阅模型钩子

@classmethod
_pre_allocate_ids_hook(cls, size, max, parent)
allocate_ids() 之前运行的钩子
@classmethod
_post_allocate_ids_hook(cls, size, max, parent, future)
allocate_ids() 之后运行的钩子
@classmethod
_pre_delete_hook(cls, key)
delete() 之前运行的钩子
@classmethod
_post_delete_hook(cls, key, future)
delete() 之后运行的钩子
@classmethod
_pre_get_hook(cls, key)
获取此模型的实体时,在 Key.get() 之前运行的钩子。
@classmethod
_post_get_hook(cls, key, future)
获取此模型的实体时,在 Key.get() 之后运行的钩子。
_pre_put_hook(self)
put() 之前运行的钩子
_post_put_hook(self, future)
put() 之后运行的钩子

内省

您可以使用这些方法来检查给定模型的属性和配置。 如果您要编写的库或函数接受多种类型的模型,这种方式很有用。

按种类查找

每个模型都有一个种类,除非重写,否则种类通常与类名称相同。您可以使用种类通过 _lookup_model 查找关联的模型类。

class Animal(ndb.Model):
    type = ndb.StringProperty()

print Animal._get_kind()  # 'Animal'
print ndb.Model._lookup_model('Animal')  # class Animal

请注意,_lookup_model 仅适用于已由应用导入的模型类。

属性

您可以使用 _properties 获取与模型关联的所有属性的列表。

class User(ndb.Model):
    name = ndb.StringProperty()
    email = ndb.StringProperty()

print User._properties
# {'email': StringProperty('email'), 'name': StringProperty('name')}

_properties 也适用于 Expando 实例

class Example(ndb.Expando):
  pass

e = Example()
e.foo = 1
e.bar = 'blah'
e.tags = ['exp', 'and', 'oh']
print e._properties
# {'foo': GenericProperty('foo'), 'bar': GenericProperty('bar'),
# 'tags': GenericProperty('tags', repeated=True)}

属性实例可进行内省。提供给构造函数的选项作为带有 _ 前缀的属性提供。

print User._properties['email']._name  # 'email'
print User._properties['email']._required  # False
print User._properties['email']._default  # None
print User._properties['email']._choices  # None
print User._properties['email']._compressed  # False
print User._properties['email']._indexed  # True
print User._properties['email']._compressed  # False
print User._properties['email']._repeated  # False
print User._properties['email']._verbose_name  # None
print isinstance(User._properties['email'], ndb.StringProperty)  # True

方法别名

Model 类中的每个方法都有一个带有 _ 前缀的别名。例如,_put() 等同于 put()。这表示,如果您始终使用带有 _ 前缀的方法,则您可以使用名称与方法名称相冲突的属性。但是请注意,您不能在构造函数中指定任何名为 keyparentid 的属性。

class MyModel(ndb.Model):
    put = ndb.StringProperty()
    query = ndb.StringProperty()
    key = ndb.StringProperty()

entity = MyModel()
entity.put = '1'
entity.query = '2'
entity.key = '3'

entity._put()
print entity
# MyModel(key=Key('MyModel', ...), put=u'1', query=u'2', key=u'3')

print MyModel._query().fetch()
# same as above.

如果要创建与任意模型交互的第三方库,建议使用带有 _ 前缀的方法。