Migração da biblioteca cliente da BD para a NDB

Não são necessárias alterações ao arquivo de dados

Caso se esteja a perguntar, apesar das diferentes APIs, o NDB e o pacote ext.db antigo escrevem exatamente os mesmos dados no Datastore. Isto significa que não tem de fazer nenhuma conversão à sua base de dados e pode combinar o código NDB e ext.db, desde que o esquema que usa seja equivalente. Pode mesmo converter entre chaves ext.db e NDB usando ndb.Key.from_old_key() e key.to_old_key().

Diferenças gerais

  • O NDB é exigente quanto aos tipos. Por exemplo, na base de dados, quando é necessária uma chave, também pode transmitir uma entidade ou uma string. No NDB, tem de transmitir uma chave.

  • O NDB é exigente em relação às listas. Por exemplo, na base de dados, db.put() aceita uma entidade ou uma lista de entidades. No NDB, usa entity.put() para colocar uma única entidade, mas ndb.put_multi(<list>) para colocar uma lista de entidades.

  • O NDB prefere métodos a funções. Por exemplo, em vez de db.get(key) e db.put(entity), a NDB usa key.get() e entity.put().

  • O NDB não gosta de oferecer duas APIs que fazem a mesma coisa. (Por outro lado, por vezes, oferece duas APIs que fazem coisas ligeiramente diferentes.)

Comparação lado a lado de chamadas API

As tabelas abaixo mostram as semelhanças e as diferenças entre o ndb e o módulo old ext.db. Consulte a documentação oficial da NDB para uma introdução e referência à NDB.

Classe do modelo

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 () !!

Entidades

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()

Não existe um equivalente direto. Consulte o artigo Stack Overflow para uma possível solução.

Obter

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')

Use as

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)

Eliminar

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)

Propriedades

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()

Sem equivalente.

db.IntegerProperty()
ndb.IntegerProperty()
db.LinkProperty()
ndb.StringProperty()

Tem um tamanho máximo de 500. Para URLs mais longos, use 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ão suportado; as strings podem sempre conter \n.

db.StringListProperty()
ndb.StringProperty(repeated=True)
db.TextProperty()
ndb.TextProperty()
db.TimeProperty()
ndb.TimeProperty()
db.UserProperty()
ndb.UserProperty()
blobstore.BlobReferenceProperty()
ndb.BlobKeyProperty()

Criar uma chave

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')

Operações principais

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()

Igualmente.

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

Transações

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)

Consultas

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

Cursores

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

No NDB, more é um valor booleano que indica se existem mais entidades no cursor.

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)