创建和使用实体键

每个实体都由一个键进行标识,该键在应用的 Datastore 实例中具有唯一性,并包含以下内容:

  • 种类。种类通常是实体所属的模型类的名称,但您可以通过替换类方法 _get_kind() 将其更改为其他字符串。
  • 标识符。您可以将自己的“键名称”指定为标识符,也可以让 Datastore 自动生成一个整数数字 ID。

指定您自己的键名称

以下示例使用命名参数 id 隐式创建带有字符串标识符的键:

account = Account(
    username='Sandy', userid=1234, email='sandy@example.com',
    id='sandy@example.com')

return account.key.id()  # returns 'sandy@example.com'

您也可以直接设置键名称:

account.key = ndb.Key('Account', 'sandy@example.com')

# You can also use the model class object itself, rather than its name,
# to specify the entity's kind:
account.key = ndb.Key(Account, 'sandy@example.com')

让 Datastore 生成用于键的 ID

此代码演示如何将自动生成的 ID 用作键:

# note: no id kwarg
account = Account(username='Sandy', userid=1234, email='sandy@example.com')
account.put()
# account.key will now have a key of the form: ndb.Key(Account, 71321839)
# where the value 71321839 was generated by Datastore for us.

在键中使用祖先路径

实体序列从根实体开始,接着从父实体到子实体,再指向给定的实体,这就构成了实体的祖先路径。实体、其父实体、父实体的父实体和以此类推得出的实体都是该实体的“祖先实体”。Datastore 中的实体形成一个与文件系统层次目录结构类似的层次键空间。

标识实体的完整键由一系列种类-标识符对构成,它们指定实体的祖先路径并以实体自身的种类-标识符对终止。Key 类的构造函数方法接受这样的种类和标识符序列,并返回表示相应实体的键的对象。

以下示例显示了按修订版本存储消息的博客服务。消息按账号进行整理,修订版本按消息进行整理。

class Revision(ndb.Model):
    message_text = ndb.StringProperty()
...
ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '1')
ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '2')
ndb.Key('Account', 'larry@example.com', 'Message', 456, 'Revision', '1')
ndb.Key('Account', 'larry@example.com', 'Message', 789, 'Revision', '2')

在示例中,('Account', 'sandy@example.com')('Message', 123)('Revision', '1') 都是种类-标识符对的示例。

请注意,Message 不是模型类;它仅用作一种将修订版本分组的方式,不用于存储数据。

如示例代码所示,实体的种类由列表中的最后一个种类-名称对指定:ndb.Key('Revision', '1')

使用命名参数

您可以使用命名参数 parent 直接指定祖先路径中的任何实体。以下所有表示法都代表相同的键:

ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '1')

ndb.Key('Revision', '1', parent=ndb.Key(
    'Account', 'sandy@example.com', 'Message', 123))

ndb.Key('Revision', '1', parent=ndb.Key(
    'Message', 123, parent=ndb.Key('Account', 'sandy@example.com')))

指定根实体

对于根实体而言,祖先路径为空,且键仅由实体自身的种类和标识符组成:

sandy_key = ndb.Key(Account, 'sandy@example.com')

指定具有祖先实体的实体

插入具有父键的新消息:

account_key = ndb.Key(Account, 'sandy@example.com')

# Ask Datastore to allocate an ID.
new_id = ndb.Model.allocate_ids(size=1, parent=account_key)[0]

# Datastore returns us an integer ID that we can use to create the message
# key
message_key = ndb.Key('Message', new_id, parent=account_key)

# Now we can put the message into Datastore
initial_revision = Revision(
    message_text='Hello', id='1', parent=message_key)
initial_revision.put()

对于通过父键创建的键,parent() 方法返回表示父实体的键:

message_key = initial_revision.key.parent()

使用数字键 ID

您可以在不指定 ID 的情况下创建实体,在这种情况下,数据存储区会自动生成一个数字 ID。如果您选择指定一些 ID,然后让 Datastore 自动生成一些 ID,则可能会违反对唯一键的要求。为了避免这种情况,请保留一个数字范围以用于选择 ID,也可使用字符串 ID 来完全避免此问题。

如需保留一组 ID,请使用模型类的 allocate_ids() 类方法:

  • 分配指定数量的 ID
  • 分配给定最大值范围内的所有 ID。

分配 ID

为给定的模型类 MyModel 分配 100 个 ID:

first, last = MyModel.allocate_ids(100)

为具有父键 p 的实体分配 100 个 ID:

first, last = MyModel.allocate_ids(100, parent=p)

返回值 firstlast 是分配的第一个和最后一个 ID(含)。您可以使用这些 ID 按照如下方式来构造键:

keys = [ndb.Key(MyModel, id) for id in range(first, last+1)]

可以保证,数据存储的内部 ID 生成器以前没有返回过这些键,对内部 ID 生成器的将来调用也不会返回这些键。但是,allocate_ids() 方法不会检查返回的 ID 是否存在于数据存储区中;它只与 ID 生成器交互。

分配给定最大值范围内的所有 ID:

first, last = MyModel.allocate_ids(max=N)

此表单确保分配少于或等于 N 的所有 ID。返回值 firstlast 表示此操作保留的 ID 范围。尝试保留已分配的 ID 不会发生错误;但如果出现这种情况,first 表示尚未分配的第一个 ID,last 是分配的最后一个 ID。