No es necesario hacer cambios en Datastore
Por si te lo preguntabas, a pesar de las diferentes APIs, NDB y el antiguo paquete ext.db escriben exactamente los mismos datos en Datastore. Esto significa que no tienes que convertir tu almacén de datos y puedes combinar código de NDB y ext.db sin problemas, siempre que el esquema que utilices sea equivalente. También puedes convertir claves ext.db y NDB con ndb.Key.from_old_key() y key.to_old_key().
Diferencias generales
NDB es exigente con los tipos. Por ejemplo, en la base de datos, cuando se requiere una clave, también puedes pasar una entidad o una cadena. En NDB, debes proporcionar una clave.
NDB es exigente con las listas. Por ejemplo, en la base de datos,
db.put()toma una entidad o una lista de entidades. En NDB, se usaentity.put()para colocar una sola entidad, perondb.put_multi(<list>)para colocar una lista de entidades.NDB prefiere los métodos a las funciones. Por ejemplo, en lugar de
db.get(key)ydb.put(entity), NDB usakey.get()yentity.put().A NDB no le gusta ofrecer dos APIs que hagan lo mismo. Por otro lado, a veces ofrece dos APIs que hacen cosas ligeramente diferentes.
Comparación de llamadas a la API en paralelo
En las tablas que se incluyen más abajo se muestran las similitudes y las diferencias entre ndb y el antiguo módulo ext.db. Consulta la documentación oficial de NDB para obtener una introducción y una referencia sobre NDB.
Clase 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()  | 
    
 No hay ningún equivalente directo. Consulta Stack Overflow para ver una posible solución.  | 
 
Obtener
| 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)  | 
 
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)  | 
 
Propiedades
| 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()  | 
    
 Sin equivalente.  | 
 
db.IntegerProperty()  | 
    
ndb.IntegerProperty()  | 
 
db.LinkProperty()  | 
    
ndb.StringProperty() Tiene un tamaño máximo de 500. Para URLs más largas, usa   | 
 
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)  | 
    
 No se admite. Las cadenas siempre pueden contener   | 
 
db.StringListProperty()  | 
    
ndb.StringProperty(repeated=True)  | 
 
db.TextProperty()  | 
    
ndb.TextProperty()  | 
 
db.TimeProperty()  | 
    
ndb.TimeProperty()  | 
 
db.UserProperty()  | 
    
ndb.UserProperty()  | 
 
blobstore.BlobReferenceProperty()  | 
    
ndb.BlobKeyProperty()  | 
 
Crear una clave
| 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')  | 
 
Operaciones con claves
| 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()  | 
    
 Lo mismo.  | 
 
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  | 
 
Transacciones
| 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) En NDB,   | 
 
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)  |