העברה של ספריית לקוח מ-DB ל-NDB

לא נדרשים שינויים ב-Datastore

למקרה שתהיתם, למרות ממשקי ה-API השונים, NDB וחבילת ext.db הישנה כותבות בדיוק את אותם נתונים ל-Datastore. זה אומר שלא צריך לבצע המרה למאגר הנתונים, ואפשר לשלב בין קוד NDB וקוד ext.db, כל עוד הסכימה שבה משתמשים שקולה. אפשר אפילו להמיר בין מפתחות ext.db לבין מפתחות NDB באמצעות ndb.Key.from_old_key() ו-key.to_old_key().

הבדלים כלליים

  • ‫NDB מאוד ספציפי לגבי סוגים. לדוגמה, במסד נתונים, כשנדרש מפתח, אפשר להעביר גם ישות או מחרוזת. ב-NDB צריך להעביר מפתח.

  • ‫NDB הוא בררן לגבי רשימות. לדוגמה, ב-db, הפונקציה db.put() מקבלת ישות או רשימה של ישויות. ב-NDB, משתמשים בפונקציה entity.put() כדי להוסיף ישות אחת, אבל בפונקציה ndb.put_multi(<list>) כדי להוסיף רשימה של ישויות.

  • ב-NDB, השימוש ב-methods עדיף על השימוש בפונקציות. לדוגמה, במקום db.get(key) ו-db.put(entity),‏ NDB משתמש ב-key.get() וב-entity.put().

  • ב-NDB לא אוהבים להציע שני ממשקי API שעושים את אותו הדבר. (מצד שני, לפעמים הוא מציע שני ממשקי API שעושים דברים קצת שונים).

השוואה של קריאות ל-API זו לצד זו

בטבלאות הבאות מוצגים קווי דמיון והבדלים בין ndb לבין מודול ext.db הישן. במסמכי NDB הרשמיים אפשר לקרוא מבוא ל-NDB ולקבל הפניה אליו.

סוג המודל

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

ישויות

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

אין מקבילה ישירה. אפשר לעיין בStack Overflow כדי למצוא פתרון אפשרי.

קבל

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

העלאה

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)

מחיקה

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)

מאפיינים

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

אין מקבילה.

db.IntegerProperty()
ndb.IntegerProperty()
db.LinkProperty()
ndb.StringProperty()

הגודל המקסימלי הוא 500. לכתובות URL ארוכות יותר, צריך להשתמש ב-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)

לא נתמך. תמיד מותר לכלול מחרוזות עם \n.

db.StringListProperty()
ndb.StringProperty(repeated=True)
db.TextProperty()
ndb.TextProperty()
db.TimeProperty()
ndb.TimeProperty()
db.UserProperty()
ndb.UserProperty()
blobstore.BlobReferenceProperty()
ndb.BlobKeyProperty()

יצירת מפתח

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

פעולות מרכזיות

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

גם אני.

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

טרנזקציות

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)

שאילתות

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

סמנים

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

ב-NDB, ‏ more הוא ערך בוליאני שמציין אם יש עוד ישויות במיקום הסמן.

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)