NDB 模型類別

繼承自 Model 類別的類別代表儲存在 Datastore 中的實體結構。應用程式會定義模型的類別來指定實體的結構,再將這些模型類別實例化來建立實體。所有模型類別均須 (直接或間接) 繼承自 Model。

本頁面中包含 API 的參考說明文件。如需總覽說明,請參閱 NDB 實體和金鑰

簡介

繼承自 Model 的類別會描述 Datastore 實體。

所有模型類別均須 (直接或間接) 繼承自 Model。您可以使用模型類別定義中的直接指派來宣告模型的結構:

from google.appengine.ext import ndb

class Person(ndb.Model):
  name = ndb.StringProperty()
  age = ndb.IntegerProperty()

您現在可以建立 Person 實體,並寫入 Datastore:

p = Person(name='Arthur Dent', age=42)
k = p.put()

put() 的傳回值為 Key,可用於稍後擷取同一個實體:

p2 = k.get()
p2 == p  # Returns True

如想更新實體,只要變更屬性並重新寫入即可。不過請注意,這麼做並不會變更金鑰:

p2.name = 'Arthur Philip Dent'
p2.put()

您也可以使用金鑰刪除實體:

k.delete()

類別主體中的屬性定義會告知系統要儲存在 Datastore 中的欄位名稱和類型、是否必須建立索引、預設值等等。資源類型有很多種。

「種類」通常與類型名稱相同 (不包括模組名稱或任何其他父項範圍)。如要覆寫類型 (可用於結構定義變更),請定義名為 _get_kind() 的類別方法,如下所示:

  class MyModel(ndb.Model):
    @classmethod
    def _get_kind(cls):
      return 'AnotherKind'

應用程式不應定義兩種相同種類的模型類別,即便這兩種類別位於不同的模型中。應用程式的類別視為全域「命名空間」。

Model 子類別可以定義大多數作業 (get、put、delete 和 allocate_ids) 呼叫前和呼叫後的掛鉤

建構函式

應用程式通常不會呼叫 Model(),但可能會呼叫繼承自 Model 的類別建構函式。這麼做會建立此模型的新例項,也就是實體。

新建立的實體不會自動寫入 Datastore。為此,您必須使用明確的 put() 呼叫將資料寫入 Datastore。

引數:

Model 子類別支援下列關鍵字引數:

key
此模型的
Key 例項。如果使用 key 參數,idparent 必須為 None (預設值)。
id
此模型的 Key ID。如果使用 id,鍵必須為 None (預設值)。
parent
父項模型的
Key 例項,或頂層模型的 None。如果使用 parentkey 必須為 None
namespace
命名空間 (該實體使用的命名空間),或 None (預設值) (使用目前的命名空間)。如果使用 namespacekey 必須為 None

應用程式也可以使用模型屬性對應的關鍵字引數,如以下所示:

class Person(ndb.Model):
  name = StringProperty()
  age = IntegerProperty()

p = Person(name='Arthur Dent', age=42)

您無法輕易定義名為「key」、「id」、「parent」或「namespace」的屬性。舉例來說,如果您在建構函式或 populate() 呼叫中傳遞 key="foo",則會設定實體的鍵,而非名為「key」的屬性屬性。

注意:如果在模型子類別中覆寫建構函式,請注意在有些情況下也會以隱含方式呼叫該建構函式,且請務必確保能支援這些呼叫。從 Datastore 讀取實體時,系統會先呼叫不含引數的建構函式來建立空白實體,然後逐一設定金鑰和屬性值。當 get_or_insert()get_or_insert_async() 建立新例項時,會將 **constructor_args 傳送至建構函式,然後再設定金鑰。

類別方法

allocate_ids(size=None, max=None, parent=None, **ctx_options)

為此模型類別分配一組鍵 ID。

引數

size
要分配的 ID 數量。您可以選擇指定 sizemax,但不能兩者同時指定。
max
要分配的 ID 數量上限。您可以選擇指定 sizemax,但不能兩者同時指定。
parent
要分配 ID 的父項鍵。
**ctx_options
內容選項

傳回包含 (start, end) 的元組,範圍包含起始和結尾。

應用程式無法在交易中呼叫 allocate_ids()

allocate_ids_async(size=None, max=None, parent=None, **ctx_options)

allocate_ids 的非同步版本。

傳回 Future 物件,其結果為分配範圍的元組 (start, end),包括範圍內的值。

get_by_id(id, parent=None, app=None, namespace=None, **ctx_options)
依據 ID 傳回實體。這其實是 Key(cls, id).get() 的簡寫。

引數

id
字串或整數鍵 ID。
parent
要取得的模型父項金鑰。
app (關鍵字引數)
應用程式 ID。如果未指定,則會取得目前應用程式的資料。
namespace (關鍵字引數)
命名空間。如果未指定,會取得預設命名空間的資料。
**ctx_options
內容選項

傳回模型例項,如果找不到,則傳回 None

get_by_id_async(id, parent=None, app=None, namespace=None, **ctx_options)
get_by_id 的非同步版本。

傳回 Future 物件,其結果是模型例項,如果找不到,則傳回 None

get_or_insert(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)
透過交易方式擷取現有實體或建立新的實體。

引數

key_name
要擷取或建立的金鑰名稱 (即字串金鑰 ID)。
parent
父項實體索引鍵 (如有)。
應用程式
應用程式 ID。如果未指定,則會取得目前應用程式的資料。
namespace
命名空間。如果未指定,會取得預設命名空間的資料。
context_options
內容選項

具有指定金鑰名稱的例項尚不存在時,此函式會將關鍵字引數傳送至模型類別建構函式。如果已存在使用提供的 key_name 和父項的例項,這些引數就會遭到捨棄。

傳回具有指定金鑰名稱和父項的 Model 類別現有例項,或剛建立的新例項。

此函式會使用交易。如果呼叫此函式的程式碼已在交易中,此函式會嘗試重複使用現有的交易。如果這個函式的實體群組與現有交易不相容,可能會導致錯誤。

get_or_insert_async(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)

這是 get_or_insert 的非同步版本。

它會傳回 Future 物件,其結果為具有指定鍵名稱和父項的現有 Model 類別例項,或是剛建立的新例項。

query([filter1, filter2, ...,] ancestor=None, app=None, namespace=None, filters=None, orders=None, default_options=None, projection=None distinct=False group_by=None)

為這個類別建立 Query 物件,如「查詢」一文所述。

關鍵字引數 distinct 為 group_by = projection 的簡寫。所有其他關鍵字引數都會傳遞至查詢建構函式

如果指定了位置引數,會使用這些引數來設定初始篩選器。

傳回 Query 物件。

實例方法

populate(**constructor_options)

設定實體的屬性值。實體的關鍵字引數會自動辨識屬性名稱,所用的方式與建構函式相同。

put(**ctx_options)

將實體的資料寫入 Datastore。傳回實體的金鑰

引數

**ctx_options
背景資訊選項
put_async(**ctx_options)

將實體的資料非同步寫入 Datastore。傳回 Future 物件。Future 物件的結果便是實體的金鑰

引數

**ctx_options
背景資訊選項
to_dict(include=all, exclude=None)

傳回包含模型屬性值的 dictStructuredPropertyLocalStructuredProperty 的屬性值會以遞迴方式轉換為字典。

引數:

include
選用要納入的屬性清單。預設值:全部。
exclude
選用的排除屬性清單。如果includeexclude 之間有重疊部分,則exclude 會「勝出」。

注意:如果屬性值是可變動的物件 (例如代表重複屬性的清單,或是儲存在 JsonProperty 中的字典或清單),除非明確轉換值 (例如 StructuredProperty 的情況),否則實體中儲存的字典會傳回相同的物件。在這類情況下,修改字典便會修改實體,反之亦然。

例項資料

key
用於儲存模型金鑰的特殊屬性。

掛鉤方法

應用程式的 Model 子類別可以將一或多個這些方法定義為作業前或作業後的「掛鉤」方法。例如,如要在每次「get」之前執行某些程式碼,請定義模型子類別的 _pre_get_hook() 方法。如需編寫鉤子函式的建議,請參閱「模型鉤子」。

@classmethod
_pre_allocate_ids_hook(cls, size, max, parent)
allocate_ids() 之前執行的掛鉤
@classmethod
_post_allocate_ids_hook(cls, size, max, parent, future)
allocate_ids() 之後執行的掛鉤
@classmethod
_pre_delete_hook(cls, key)
delete() 之前執行的掛鉤
@classmethod
_post_delete_hook(cls, key, future)
delete() 之後執行的掛鉤
@classmethod
_pre_get_hook(cls, key)
取得這個模型的實體時,在 Key.get() 之前執行的
掛鉤。
@classmethod
_post_get_hook(cls, key, future)
取得這個模型的實體時,在 Key.get() 之後執行的掛鉤。
_pre_put_hook(self)
put() 之前執行的掛鉤
_post_put_hook(self, future)
put() 之後執行的掛鉤

自我檢查

您可以使用這些方法檢查特定模型的屬性和設定。如果您要編寫可接受多種模型類型的程式庫或函式,這項功能就非常實用。

依種類查詢

每個模型都具有「類型」。除非遭到覆寫,否則類型通常與類別名稱相同。您可以使用 _lookup_model 的類別來尋找相關聯的模型類別。

class Animal(ndb.Model):
    type = ndb.StringProperty()

print Animal._get_kind()  # 'Animal'
print ndb.Model._lookup_model('Animal')  # class Animal

請注意,_lookup_model 僅適用於應用程式已匯入的模型類別。

屬性

您可以使用 _properties 取得模型所有相關屬性的清單。

class User(ndb.Model):
    name = ndb.StringProperty()
    email = ndb.StringProperty()

print User._properties
# {'email': StringProperty('email'), 'name': StringProperty('name')}

_properties 也適用於 Expando 項目

class Example(ndb.Expando):
  pass

e = Example()
e.foo = 1
e.bar = 'blah'
e.tags = ['exp', 'and', 'oh']
print e._properties
# {'foo': GenericProperty('foo'), 'bar': GenericProperty('bar'),
# 'tags': GenericProperty('tags', repeated=True)}

您可以檢查屬性的項目。提供給建構函式的選項是以 _ 開頭的屬性。

print User._properties['email']._name  # 'email'
print User._properties['email']._required  # False
print User._properties['email']._default  # None
print User._properties['email']._choices  # None
print User._properties['email']._compressed  # False
print User._properties['email']._indexed  # True
print User._properties['email']._compressed  # False
print User._properties['email']._repeated  # False
print User._properties['email']._verbose_name  # None
print isinstance(User._properties['email'], ndb.StringProperty)  # True

方法別名

Model 類別的每個方法都有以 _ 開頭的別名,舉例來說,_put() 相當於 put()。也就是說,如果您一律使用 _ 開頭的方法,就能使用與方法名稱衝突的屬性名稱。不過請注意,您無法在建構函式中指定任何名為 keyparentid 的屬性。

class MyModel(ndb.Model):
    put = ndb.StringProperty()
    query = ndb.StringProperty()
    key = ndb.StringProperty()

entity = MyModel()
entity.put = '1'
entity.query = '2'
entity.key = '3'

entity._put()
print entity
# MyModel(key=Key('MyModel', ...), put=u'1', query=u'2', key=u'3')

print MyModel._query().fetch()
# same as above.

如要建立能與任何模型互動的第三方資料庫,建議您使用以 _ 開頭的方法。