Migrer la bibliothèque cliente DB vers NDB

Aucun changement requis au niveau de Datastore

Au cas où vous vous poseriez la question, sachez que même si les API sont différentes, NDB et l'ancien package ext.db écrivent exactement les mêmes données dans Datastore. Cela signifie que vous n'avez aucune conversion à faire dans votre datastore et que vous pouvez panacher à volonté les API NDB et ext.db dans votre code, à condition que le schéma que vous utilisez soit équivalent. Vous pouvez même effectuer des conversions entre clés ext.db et NDB au moyen des méthodes ndb.Key.from_old_key() et key.to_old_key().

Différences générales

  • NDB est pointilleux au sujet des types. Par exemple, avec db, lorsqu'une clé est requise, vous pouvez transmettre aussi bien une entité qu'une chaîne. Avec NDB, vous devez impérativement transmettre une clé.

  • NDB est pointilleux au sujet des listes. Par exemple, avec db, db.put() accepte aussi bien une entité qu'une liste d’entités. Avec NDB, vous devez faire appel à entity.put() pour insérer une entité unique, mais utiliser ndb.put_multi(<list>) dans le cas d'une liste d'entités.

  • NDB préfère les méthodes aux fonctions. Par exemple, au lieu des fonctions db.get(key) et db.put(entity), NDB utilise les méthodes key.get() et entity.put().

  • NDB évite de proposer deux API réalisant la même action. (Toutefois, il peut proposer deux API effectuant des opérations légèrement différentes.)

Comparatif des appels API

Les tableaux ci-dessous illustrent les similitudes et les différences entre ndb et l'ancien module ext.db. Consultez la documentation officielle de NDB pour une introduction et une documentation de référence complète sur NDB. Cet article de blog de Dylan Vassallo, stagiaire à la Khan Academy, sur la mise à niveau de modèles vers NDB, peut également vous intéresser.

Classe de modèle

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

Entités

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

Pas d'équivalent direct. Pour une solution possible, reportez-vous à Stack Overflow.

Obtenir

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

Écrire

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)

Supprimer

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)

Propriétés

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

Aucun équivalent.


db.IntegerProperty()

ndb.IntegerProperty()

db.LinkProperty()

ndb.StringProperty()

Possède une taille maximale de 500. Pour des URL plus longues, utilisez 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)

Non compatible. Les chaînes peuvent toujours contenir le caractère \n.


db.StringListProperty()

ndb.StringProperty(repeated=True)

db.TextProperty()

ndb.TextProperty()

db.TimeProperty()

ndb.TimeProperty()

db.UserProperty()

ndb.UserProperty()

blobstore.BlobReferenceProperty()

ndb.BlobKeyProperty()

Construire une clé

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

Opérations de clé

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

Identique.


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

Transactions

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)

Requêtes

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

Curseurs


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

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

Dans NDB, more est une valeur booléenne indiquant s'il y a davantage d'entités au niveau du curseur.


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)
Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Environnement standard App Engine pour Python 2