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

从 DB 客户端库迁移到 NDB 客户端库

无需对 Datastore 进行任何更改

需要指明的是,尽管属于不同的 API,但 NDB 和旧版 ext.db 软件包会向 Datastore 写入完全相同的数据。这意味着您不必对数据存储区执行任何转换操作,并且可以放心地将 NDB 与 ext.db 代码搭配在一起使用,但前提是您使用的架构是等效的。您甚至可以使用 ndb.Key.from_old_key()key.to_old_key() 在 ext.db 和 NDB 键之间进行转换。

一般差异

  • NDB 对类型很挑剔。例如,在 DB 中,当需要键时,您也可以传递实体或字符串;而在 NDB 中,您必须传递键。

  • NDB 对列表很挑剔。例如,在 DB 中,db.put() 采用一个实体或一系列实体。在 NDB 中,您可以使用 entity.put() 放置单个实体,但使用 ndb.put_multi(<list>) 放置一系列实体。

  • NDB 更喜欢方法而非函数。例如,NDB 会使用 key.get()entity.put(),而不使用 db.get(key)db.put(entity)

  • NDB 不喜欢提供两个做同样事情的 API。(从另一方面讲,它有时会提供两个所做事情略微不同的 API。)

并排显示的 API 调用比较情况

下表显示了 NDB 与旧版 ext.db 模块之间的相似之处和不同之处。如需查看 NDB 的简介和参考,请参阅官方 NDB 文档。您还可以参阅可汗学院实习生 Dylan Vassallo 撰写的有关将模型升级到 NDB 的博客文章

Model 类

google.appengine.ext.db ndb.model

class MyModel(db.Model):
  foo = db.StringProperty()

class MyModel(ndb.Model):
  foo = ndb.StringProperty()

@classmethod
def kind(cls):
  return 'Foo'

@classmethod
def _get_kind(cls):
  return 'Foo'

MyModel.kind()

MyModel._get_kind()

MyModel.properties()
model_instance.properties()

MyModel._properties  # No () !!
model_entity._properties

MyExpando.dynamic_properties()

MyExpando._properties  # No () !!

实体

google.appengine.ext.db ndb.model

MyModel(key_name='my_key')

MyModel(id='my_key')

MyModel(key_name='my_key',
  parent=model_instance)

MyModel(id='my_key',
  parent=model_instance.key)

key = model_instance.key()

key = model_instance.key  # No () !!

model_instance = MyModel(
  foo='foo',
  bar='bar',
  baz='baz')

model_instance = MyModel(
  foo='foo',
  bar='bar',
  baz='baz')

model_instance.foo = 'foo'
model_instance.bar = 'bar'
model_instance.baz = 'baz'

model_instance.foo = 'foo'
model_instance.bar = 'bar'
model_instance.baz = 'baz'
# or a shortcut...
model_instance.populate(
  foo='foo',
  bar='bar',
  baz='baz')

model_instance.is_saved()

无直接对等项;如需查看可能的解决方案,请参阅 Stack Overflow

获取

google.appengine.ext.db ndb.model

MyModel.get_by_key_name('my_key')

MyModel.get_by_id('my_key')

MyModel.get_by_id(42)

MyModel.get_by_id(42)

db.get(key)

key.get()

MyModel.get(key)

key.get()

db.get(model_instance)

model_instance.key.get()

db.get(list_of_keys)

ndb.get_multi(list_of_keys)

db.get(list_of_instances)

ndb.get_multi([x.key for x in
               list_of_instances])

MyModel.get_or_insert('my_key',
  parent=model_instance,
  foo='bar')

MyModel.get_or_insert('my_key',
  parent=model_instance.key,
  foo='bar')

放置

google.appengine.ext.db ndb.model

db.put(model_instance)

model_instance.put()

db.put(list_of_model_instances)

ndb.put_multi(
  list_of_model_instances)

删除

google.appengine.ext.db ndb.model

model_instance.delete()

model_instance.key.delete()

db.delete(model_instance)

model_instance.key.delete()

db.delete(key)

key.delete()

db.delete(list_of_model_instances)

ndb.delete_multi([m.key for m in
  list_of_model_instances])

db.delete(list_of_keys)

ndb.delete_multi(list_of_keys)

属性

google.appengine.ext.db ndb.model

db.BlobProperty()

ndb.BlobProperty()

db.BooleanProperty()

ndb.BooleanProperty()

db.ByteStringProperty()

ndb.BlobProperty(indexed=True)

db.CategoryProperty()

ndb.StringProperty()

db.DateProperty()

ndb.DateProperty()

db.DateTimeProperty()

ndb.DateTimeProperty()

db.EmailProperty()

ndb.StringProperty()

db.FloatProperty()

ndb.FloatProperty()

db.GeoPtProperty()

ndb.GeoPtProperty()

db.IMProperty()

无对等项。


db.IntegerProperty()

ndb.IntegerProperty()

db.LinkProperty()

ndb.StringProperty()

大小上限为 500。对于较长的网址,请使用 ndb.TextProperty()。)


db.ListProperty(bool)
db.ListProperty(float)
db.ListProperty(int)
db.ListProperty(db.Key)
# etc.

ndb.BooleanProperty(repeated=True)
ndb.FloatProperty(repeated=True)
ndb.IntegerProperty(repeated=True)
ndb.KeyProperty(repeated=True)
# etc.

db.PhoneNumberProperty()

ndb.StringProperty()

db.PostalAddressProperty()

ndb.StringProperty()

db.RatingProperty()

ndb.IntegerProperty()

db.ReferenceProperty(AnotherModel)
model_instance.prop
MyModel.prop \
  .get_value_for_datastore \
  (model_instance)

ndb.KeyProperty(kind=AnotherModel)
model_instance.prop.get()
model_instance.prop

# Using the backreference set
other = model_instance.prop
other.prop_set.fetch(N)

# No direct equivalent; emulation:
other = model_instance.prop.get()
MyModel.query(
  MyModel.prop == other.key).fetch(N)

db.SelfReferenceProperty()

ndb.KeyProperty(kind='ThisModelClass')

db.StringProperty()

ndb.StringProperty()

db.StringProperty(multiline=True)

不支持;字符串始终允许包含 \n


db.StringListProperty()

ndb.StringProperty(repeated=True)

db.TextProperty()

ndb.TextProperty()

db.TimeProperty()

ndb.TimeProperty()

db.UserProperty()

ndb.UserProperty()

blobstore.BlobReferenceProperty()

ndb.BlobKeyProperty()

构建键

google.appengine.ext.db ndb.model

key = db.Key(encoded_key)

key = ndb.Key(urlsafe=encoded_key)

key = db.Key.from_path(
  'MyKind', 'some_id',
  'MyKind', 'some_id')

key = ndb.Key(
  'MyKind', 'some_id',
  'MyKind', 'some_id')

key = db.Key.from_path(
  MyModel, 'some_id',
  parent=model_instance,
  namespace='my_namespace')

key = ndb.Key(
  MyModel, 'some_id',
  parent=model_instance.key,
  namespace='my_namespace')

键操作

google.appengine.ext.db ndb.model

key.id_or_name()

key.id()

key.id()

key.integer_id()

key.name()

key.string_id()

key.has_id_or_name()

key.id() is None
# or...
model_instance.has_complete_key()

key.app(), key.namespace(),
key.parent(), key.kind()

相同。


str(key)

key.urlsafe()

key.to_path()

key.flat()

db.allocate_ids(MyModel, size)

S, E = MyModel.allocate_ids(size)

db.allocate_id_range(MyModel,X,Y)

S, E = MyModel.allocate_ids(max=Y)
assert S <= X

事务

google.appengine.ext.db ndb.model

db.run_in_transaction(function)

ndb.transaction(function)

db.run_in_transaction(
  function, *args, **kwds)

ndb.transaction(
  lambda: function(*args, **kwds))

db.run_in_transaction_custom_retries(n, function)

ndb.transaction(function, retries=n)

opts = \
  db.create_transaction_options(xg=True)
db.run_in_transaction_options(opts, fun)

ndb.transaction(fun, xg=True)

查询

google.appengine.ext.db ndb.model

q = MyModel.all()

q = MyModel.query()

for result in q.run(): ...

for result in q.iter(): ...

q = MyModel.all() \
  .filter('foo =', 'bar') \
  .filter('baz >=', 'ding')

q = MyModel.query(
  MyModel.foo == 'bar',
  MyModel.baz >= 'ding')

q = MyModel.all()
q.filter('foo =', 'bar')
q.filter('baz >=', 'ding')
q.order('-foo')
results = q.fetch(10)

q = MyModel.query()
q = q.filter(MyModel.foo == 'bar')
q = q.filter(MyModel.baz >= 'ding')
q = q.order(-MyModel.foo)
results = q.fetch(10)

q.filter('__key__', k)
# k is a db.Key instance

q = q.filter(MyModel._key == k)
# k is an ndb.Key instance

a.filter('__key__ >=', k)
# k is a db.Key instance

q = q.filter(MyModel._key >= k)
# k is an ndb.Key instance

class MyExpando(Expando): pass
q = MyExpando.all()
q.filter('foo =', 'bar')

class MyExpando(Expando): pass
q = MyExpando.query(
 ndb.GenericProperty('foo') == 'bar')

class Foo(Model): ...
class Bar(Model):
  foo = ReferenceProperty(Foo)
myfoo = <some Foo instance>
for bar in myfoo.bar_set(): ...

class Foo(Model): ...
class Bar(Model):
  foo = KeyProperty(kind=Foo)
myfoo = <some Foo instance>
for bar in \
  Bar.query(Bar.foo == myfoo.key): ...

q = MyModel.all()
q.ancestor(ancestor_key)

q =
  MyModel.query(ancestor=ancestor_key)

q = MyModel.all(keys_only=True)
r = q.fetch(N)

r = MyModel.query() \
    .fetch(N, keys_only=True)
# Alternatively:
q = MyModel.query(
      default_options=QueryOptions(
                      keys_only=True))
r = q.fetch(N)

q = MyModel.gql(...)

# same thing

游标


q = MyModel.all()
a = q.fetch(20)
cur = q.cursor()

q = MyModel.query()
a, cur, more = q.fetch_page(20)

在 NDB 中,more 是布尔值,用来指明游标上是否有更多实体。


q.with_cursor(cur)
b = q.fetch(20)

b, cur, more = \
  q.fetch_page(20, start_cursor=cur)

q.with_cursor(end_cursor=cur)
b = q.fetch(20)

q.fetch(20, end_cursor=cur)