DB to NDB Client Library Migration

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

  • NDB is picky about types. E.g. in db, when a key is required, you can also pass an entity or a string. In NDB you must pass a key.

  • NDB is picky about lists. E.g. in db, db.put() takes either an entity or a list of entities. In NDB, you use entity.put() to put a single entity, but ndb.put_multi(<list>) to put a list of entities.

  • NDB prefers methods over functions. E.g. instead of db.get(key) , and db.put(entity) , NDB uses key.get() and entity.put() .

  • NDB doesn't like offering two APIs that do the same thing. (On the other hand it does sometimes offer two APIs that do slightly different things.)

Side-by-side API call comparison

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.

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

Has a max size of 500. For 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 
 ) 
 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.

 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 
 ) 

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

 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 
 ) 
Create a Mobile Website
View Site in Mobile | Classic
Share by: