My favorites | 中文(简体) | Sign in

创建、获取和删除数据

数据存储区 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)

使用 Query 获取实体

数据存储区可用在指定类型的实体之间执行查询。查询可以使用实体属性值必须满足的条件过滤结果,并可以返回按属性值排序的结果。查询还可以用指定的祖先限制实体的范围,请参阅键和实体组

有关查询的工作方式的完整说明,包括一些查询无法执行的操作,请参阅查询和索引

数据存储区 API 提供两种接口用于对实体属性执行查询:Query,这是一种使用 Query 对象上的方法来准备查询的接口;GqlQuery,这是一种使用名为 GQL 的查询语言(类似于 SQL)的接口。

Query 接口

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 接口

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 对象。

执行查询和访问结果

QueryGqlQuery 对象在应用程序尝试访问结果之前不会执行查询。当应用程序访问结果时会执行查询,且结果会作为查询的 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 获取实体

将实体存储在数据存储区中后,该实体将具有唯一的键。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() 执行该操作,然后在访问属性前测试返回值。

删除作为其他实体的祖先的实体不会影响这些子实体。只要应用程序不依赖于祖先的存在构建子孙实体的键,应用程序将仍能够访问子孙实体。