Python 2 wird von der Community nicht mehr unterstützt. Wir empfehlen die Migration von Python 2-Anwendungen zu Python 3.

Migration von DB- zu NDB-Clientbibliotheken

Keine Datenspeicheränderungen erforderlich

Trotz der unterschiedlichen APIs werden von NDB und dem früheren ext.db-Paket genau dieselben Daten in den Datenspeicher geschrieben. Daher sind keine Konvertierungen in Ihrem Datenspeicher erforderlich und Sie können NDB und ext.db-Code nach Belieben kombinieren, solange das verwendete Schema äquivalent ist. Sie haben sogar die Möglichkeit, mithilfe von ndb.Key.from_old_key() und key.to_old_key() Konvertierungen zwischen ext.db- und NDB-Schlüsseln vorzunehmen.

Allgemeine Unterschiede

  • NDB ist wählerisch in Bezug auf Typen. Wenn beispielsweise in db ein Schlüssel erforderlich ist, können Sie auch eine Entität oder einen String übergeben. In NDB müssen Sie einen Schlüssel übergeben.

  • NDB ist wählerisch in Bezug auf Listen. Beispiel: In db verwendet db.put() entweder eine Entität oder eine Liste von Entitäten. In NDB verwenden Sie entity.put() zum Einfügen einer einzelnen Entität, aber ndb.put_multi(<list>) zum Einfügen einer Liste von Entitäten.

  • NDB bevorzugt Methoden gegenüber Funktionen. Beispielsweise verwendet NDB anstelle von db.get(key) und db.put(entity) key.get() und entity.put().

  • NDB bietet ungern zwei APIs an, die dasselbe tun. Stattdessen werden manchmal zwei APIs mit etwas anderen Funktionen angeboten.

Gegenüberstellung von API-Aufrufen

In den folgenden Tabellen sehen Sie die Ähnlichkeiten und Unterschiede zwischen NDB und dem früheren ext.db-Modul. Eine Einführung und Referenzen zu NDB finden Sie in der offiziellen NDB-Dokumentation. Es empfiehlt sich außerdem, den Blogbeitrag von Dylan Vassallo, Mitarbeiter der Khan Academy, über das Upgraden von Modellen für NDB zu lesen.

Modellklasse

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äten

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

Kein direktes Äquivalent, siehe Stack Overflow für eine mögliche Lösung.

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)

Properties

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

Kein Äquivalent.


db.IntegerProperty()

ndb.IntegerProperty()

db.LinkProperty()

ndb.StringProperty()

Hat eine maximale Größe von 500. Verwenden Sie für längere URLs 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)

Nicht unterstützt. Strings dürfen immer \n enthalten.


db.StringListProperty()

ndb.StringProperty(repeated=True)

db.TextProperty()

ndb.TextProperty()

db.TimeProperty()

ndb.TimeProperty()

db.UserProperty()

ndb.UserProperty()

blobstore.BlobReferenceProperty()

ndb.BlobKeyProperty()

Schlüssel erstellen

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

Schlüsselvorgänge

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

Gleich.


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

Transaktionen

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)

Abfragen

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

Cursors


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

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

In NDB ist more ein boolescher Wert, der angibt, ob am Cursor weitere Entitäten vorhanden sind.


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)