数据存储区 API 代表作为 Model 类实例的实体。Model 实例创建、更新和删除实体的方法。可以使用 Query 或 Key,以 Model 实例的形式从数据存储区抓取实体。
Model(和 Expando)类的实例代表数据存储区实体。应用程序通过调用对应类别的 Model 类的构造函数来创建指定类别的新实体。
pet = Pet(name="Fluffy",
type="cat",
owner=users.get_current_user())
新实体不会在数据存储区中创建,直至第一次“放置”该实例,方式是通过对实例调用 put() 方法,或通过将实例传递到 db.put() 函数。
pet.put() db.put(pet)
如果之前已经存储了实例,则 put() 方法会更新现有实体。
查询以 Model 实例的形式返回结果。这些实体可以进行修改并放回到数据存储区中。
if users.get_current_user():
user_pets = db.GqlQuery("SELECT * FROM Pet WHERE owner = :1",
users.get_current_user())
for pet in user_pets:
pet.spayed_or_neutered = True
db.put(user_pets)
数据存储区可用在指定类型的实体之间执行查询。查询可以使用实体属性值必须满足的条件过滤结果,并可以返回按属性值排序的结果。查询还可以用指定的祖先限制实体的范围,请参阅键和实体组。
有关查询的工作方式的完整说明,包括一些查询无法执行的操作,请参阅查询和索引。
数据存储区 API 提供两种接口用于对实体属性执行查询:Query,这是一种使用 Query 对象上的方法来准备查询的接口;GqlQuery,这是一种使用名为 GQL 的查询语言(类似于 SQL)的接口。
Model(或 Expando)类上的 all() 方法返回代表对应类别的所有实体查询的 Query 对象。应用程序通过在对象上调用 filter()、order() 和 ancestor() 方法来准备查询。
class Story(db.Model):
title = db.StringProperty()
date = db.DateTimeProperty()
query = Story.all()
query.filter('title =', 'Foo')
query.order('-date')
query.ancestor(key)
# These methods can be chained together on one line.
query.filter('title =', 'Foo').order('-date').ancestor(key)
GqlQuery 类构造函数使用 GQL 查询字符串和可选的参数进行绑定。查询字符串指定类型、过滤器、排序顺序和祖先条件。查询字符串还可以包含结果限制和偏移。
# Parameters can be bound with positional arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :1 "
"AND ANCESTOR IS :2 "
"ORDER BY date DESC",
'Foo', key)
# Or, parameters can be bound with keyword arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :title "
"AND ANCESTOR IS :parent "
"ORDER BY date DESC",
title='Foo', parent=key)
# String, number and Boolean values can be literal values in the string.
query = db.GqlQuery("SELECT * FROM Story WHERE title = 'Foo' "
"AND ANCESTOR IS :parent "
"ORDER BY date DESC",
parent=key)
Model 类的 gql() 类方法还可以准备来自字符串的 GqlQuery 对象。该字符串是忽略了 SELECT * FROM Model 的 GQL 查询字符串,因为该部分是暗含的。
query = Story.gql("WHERE title = :title "
"AND ANCESTOR IS :parent "
"ORDER BY date DESC",
title='Foo', parent=key)
参数绑定可以使用 bind() 方法重新绑定到新值。应用程序可以通过重新绑定参数和重新执行查询来重复使用 GqlQuery 对象。
Query 和 GqlQuery 对象在应用程序尝试访问结果之前不会执行查询。当应用程序访问结果时会执行查询,且结果会作为查询的 Model 类的实例加载到内存中。两种 Query 类都提供两种执行查询和访问结果的方式:fetch() 方法和迭代器接口。
fetch() 方法会使用最大数目的结果来抓取(限制),并会跳过可选数目的结果(偏移)。该方法会执行查询,然后抓取结果,直至达到限制或没有更多的结果为止。一旦将结果加载到内存中,它将跳过偏移(如果指定了偏移),然后以 Model 实例的列表形式返回请求的结果。将针对每个对 fetch() 的调用执行完全查询。
注意:偏移不影响从数据存储区抓取的结果的数量。将会抓取所有结果直至达到限制为止,并将其存储在内存中。偏移仅影响 fetch() 方法返回的内容。
results = query.fetch(10) for result in results: print "Title: " + result.title
指定给 fetch() 方法的限制和偏移覆盖任何在 GQL 查询字符串中指定的限制和偏移。
如果 Query 对象用作迭代器,则查询将在没有限制或偏移的情况下执行,结果会加载到内存中,且返回的值是结果上的迭代器。迭代器产生 Model 类的实例。
for result in query: print "Title: " + result.title
注意:数据存储区最多能返回 1000 个结果来响应查询,与用于抓取结果的限制和偏移无关。1000 个结果包含了任何使用偏移跳过的结果,所以如果结果超过 1000 个的查询使用 100 作为偏移,则会返回 900 个结果。
将实体存储在数据存储区中后,该实体将具有唯一的键。Key 值在 API 中表达为 Key 类的实例。Model 实例的 put() 方法和 db.put() 函数返回存储的实体的 Key。首次存储 Model 实例后,Model 实例的 key() 方法将返回实例的 Key。
entity.put() key = entity.key() # ... entity = db.get(key)
Key 值的常见用法是将其存储为另一个实体上的属性的值。ReferenceProperty Model Property 类提供对 Model 实例(以键的形式)的自动引用和取消引用:Model 实例可以直接分配给 ReferenceProperty,并且它的键会被用作值。
class PetOwner(db.Model): name = db.StringProperty() class Pet(db.Model): name = db.StringProperty() owner = db.ReferenceProperty(PetOwner) owner = PetOwner(name="Albert") pet = Pet(name="Fluffy", owner=owner) # This is equivalent: pet = Pet(name="Fluffy", owner=owner.key())
同样,通过属性访问的 ReferenceProperty 值的行为类似其实例。数据实体自动抓取,并且在使用时才抓取。
pets = db.GqlQuery("SELECT * FROM Pet WHERE name = :1", "Fluffy")
pet = pets.get()
owner_name = pet.owner.name
不使用 ReferenceProperty 模型(例如采用 Expando 动态属性或 ListProperty 元素)存储的键值没有自动取消引用的行为。
db.get() 函数从数据存储区抓取实例以获得一个 Key(或 Key 的列表)。
Key 可以编码为字符串,以便在应用程序外部传递。要将编码为字符串的键转换回 Key 对象,应用程序会将该字符串传递到 Key 构造函数。
obj = MyModel(name="Foo")
self.response.write('<a href="/view?key=%s">%s</a>' % (str(obj.key()),
obj.name()))
# ...
key_name = self.request.get('key')
obj = db.get(db.Key(key_name))
注意:Key 的字符串编码是不透明的,但不进行加密。如果您的应用程序要使键无法猜测,您应在将其发送给用户之前进一步加密字符串编码的 Key。
应用程序可以使用 Model 实例或 Key 从数据存储区中删除实体。Model 实例的 delete() 方法会从数据存储区中删除对应的实体。delete() 函数采用 Key 或 Key 的列表并从数据存储区中删除实体。
q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
for result in results:
result.delete()
# or...
q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
db.delete(results)
删除实体不会更改数据存储区中可能参考该实体的 Key 值。如果您的应用程序可以尝试取消引用删除的实体的 Key 值,则该应用程序应使用 db.get() 执行该操作,然后在访问属性前测试返回值。
删除作为其他实体的祖先的实体不会影响这些子实体。只要应用程序不依赖于祖先的存在构建子孙实体的键,应用程序将仍能够访问子孙实体。