No se necesitan cambios en Datastore
En caso de duda, NDB y el paquete antiguo ext.db escriben exactamente los mismos datos en Datastore, a pesar de que las API sean diferentes. Eso significa que no tienes que hacer ninguna conversión en tu almacén de datos y que puedes mezclar y combinar los códigos NDB y ext.db sin inconvenientes, siempre que el esquema que uses sea equivalente. Incluso puedes convertir entre claves ext.db y NDB con ndb.Key.from_old_key() y key.to_old_key().
Diferencias generales
NDB es meticuloso en cuanto a los tipos. P. ej., en la base de datos, también puedes pasar una entidad o una string cuando se requiere una clave. En NDB debes pasar una clave.
NDB es meticuloso en cuanto a las listas. P. ej., en db,
db.put()
toma una entidad o una lista de entidades. En NDB, usasentity.put()
para poner una sola entidad, perondb.put_multi(<list>)
a fin de poner una lista de entidades.NDB prefiere los métodos a las funciones. P. ej., en lugar de
db.get(key)
ydb.put(entity)
, NDB usakey.get()
yentity.put()
.A NDB no le gusta ofrecer dos API que realicen las mismas acciones (por otra parte, en algunos casos, cuenta con dos API que realizan acciones ligeramente diferentes).
Comparación de llamadas a la API en paralelo
Las tablas a continuación muestran similitudes y diferencias entre ndb y el módulo antiguo ext.db. Consulta los documentos oficiales de NDB a fin de obtener una introducción y una referencia para NDB.
Clase 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 () !! |
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 equivalente directo; consulta Ampliación de pila para obtener una solución posible. |
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) |
Borrar
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() |
No hay equivalente. |
db.IntegerProperty() |
ndb.IntegerProperty() |
db.LinkProperty() |
ndb.StringProperty() Tiene un tamaño máximo de 500. Para URL
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 es compatible; las strings 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() |
Compilación de claves
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 de 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() |
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 |
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) |