Google
« All Docs
NDB Cheat Sheet

NDB Cheat Sheet

rodrigo.moraes@gmail.com, guido@google.com

(last update: 8/7/2013)

Cheat Sheet: ext.db to ndb

The tables below show similarities and differences between ndb and the old ext.db module. See the Official NDB Docs for an introduction to and reference for NDB. You may also be interested in a blog entry by Khan Academy intern Dylan Vassallo about upgrading models to NDB.

No Datastore Changes Needed!

In case you wondered, despite the different APIs, NDB and the old ext.db package write exactly the same data to the Datastore. That means you don’t have to do any conversion to your datastore, and you can happily mix and match NDB and ext.db code, as long as the schema you use is equivalent. You can even convert between ext.db and NDB keys using ndb.Key.from_old_key() and key.to_old_key().

General differences

[TBD: Maybe also list some things that are the same?]

[TBD: What else is part of the synchronous API?]

[TBD: Add direct links to docs in table]

Model class

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[a][b] () !!

model_entity._properties

MyExpando.dynamic_properties()

MyExpando._properties  # No () !!

Entities

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 direct equivalent; see http://stackoverflow.com/questions/12083254/is-it-possible-to-determine-with-ndb-if-model-is-persistent-in-the-datastore-or/12096066#12096066 for a possible solution

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

# No equivalent

db.IntegerProperty()

ndb.IntegerProperty()

db.LinkProperty()

ndb.StringProperty() (but beware the max size of 500 -- if you have longer urls, use 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)[c][d][e]

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)

# Not supported; strings are always

# allowed to contain '\n'

db.StringListProperty()

ndb.StringProperty(repeated=True)

db.TextProperty()

ndb.TextProperty()

db.TimeProperty()

ndb.TimeProperty()

db.UserProperty()

ndb.UserProperty()

blobstore.BlobReferenceProperty()

ndb.BlobKeyProperty()

Building a Key

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

Key operations

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

# same thing

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)

Queries

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)

# (1)

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)

(1) In NDB, more is a bool indicating whether there are more entities at the cursor.

[f]

[g]

[a]Wouldn't we want to avoid using a protected attribute from the class? That said, the best non-protected workaround I've found so far is MyModel.to_dict().keys().

[b]No, _properties (both class and instance attr) are documented for this purpose. They start with underscore to avoid polluting the namespace for allowable Property names. The to_dict() trick is fragile and expensive.

[c]what does

agency = db.ReferenceProperty ( AnotherModel, collection_name = "model_collection" )

translate to when using ndb?

[d]I think:

agency = ndb.KeyProperty(kind='AnotherModel')

But for the model_collection backreference, you'll have to build a query on model_collection with a filter to reference the entity keys (doesn't have a name in your example).

[e]thanks, I was thinking a similar functionality had been built in.

[f]How do you specify the equivalent of the collection_name property in NDB?

[g]thanks, fixed!