O Python 2 não é mais compatível com a comunidade. Recomendamos que você migre aplicativos do Python 2 para o Python 3.

Migração da biblioteca de cliente DB para NDB

Nenhuma alteração do Datastore é necessária

Caso você tenha se perguntado, mesmo com as diferentes APIs, o NDB e o antigo pacote ext.db gravam exatamente os mesmos dados no Datastore. Isso significa que você não precisa fazer nenhuma conversão para o armazenamento de dados, podendo misturar e combinar código do NDB e do ext.db como quiser, contanto que o esquema usado seja equivalente. É possível até mesmo converter as chaves ext.db e NDB usando ndb.Key.from_old_key() e key.to_old_key().

Diferenças gerais

  • O NDB é exigente a respeito de tipos. Por exemplo, no db, quando uma chave é necessária, você também pode passar uma entidade ou uma string. No NDB você precisa passar uma chave.

  • O NDB é exigente a respeito de listas. Por exemplo, no db, db.put() usa uma entidade ou uma lista de entidades. No NDB, você 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), o NDB usa key.get() e entity.put().

  • O NDB não oferece duas APIs que fazem a mesma coisa. Por outro lado, às vezes, oferece duas APIs que fazem coisas ligeiramente diferentes.

Comparação de chamadas de API lado a lado

Nas tabelas abaixo, veja as semelhanças e diferenças entre o ndb e o antigo módulo ext.db. Consulte a documentação oficial do NDB para uma introdução e uma referência sobre o NDB. Talvez você também se interesse por uma postagem do blog feita pelo estagiário da Khan Academy, Dylan Vassallo, sobre o upgrade de modelos para o NDB.

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

Nenhum equivalente direto. Consulte Stack Overflow para uma possível solução.

Get

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

Put

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)

Delete

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

Não há 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)

Incompatível. Strings sempre podem conter \n.


    db.StringListProperty()

    ndb.StringProperty(repeated=True)

    db.TextProperty()

    ndb.TextProperty()

    db.TimeProperty()

    ndb.TimeProperty()

    db.UserProperty()

    ndb.UserProperty()

    blobstore.BlobReferenceProperty()

    ndb.BlobKeyProperty()

Como 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 de chave

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

Igual.


    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 booleano que indica se há 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)