自 Model 類別繼承的類別代表了儲存在 Datastore 中的實體相關結構。應用程式會定義模型的類別來指定實體的結構,再將這些模型類別實例化來建立實體。所有模型類別均須 (直接或間接) 繼承自模型。
本頁面中包含 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()
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參數,id和parent必須為None(預設值)。 - id
- 這個模型的金鑰 ID。如果使用
id,金鑰必須為None(預設值)。 - parent
- 父項模型的金鑰項目。如為頂層模型,則為
None。如果使用parent,key必須為None。 - 命名空間
- 該實體使用的命名空間。如要使用現有的命名空間,則為
None(預設值)。 如果使用namespace,key必須為None。
應用程式也可以使用模型屬性對應的關鍵字引數,如以下所示:
class Person(ndb.Model): name = StringProperty() age = IntegerProperty() p = Person(name='Arthur Dent', age=42)
您無法輕鬆定義名為「key」、「id」、「parent」或「namespace」的屬性。舉例來說,如果您在建構函式或 key="foo" 呼叫中傳遞 populate(),系統會設定實體的鍵,而不是名為「key」的屬性屬性。
注意:如果在模型子類別中覆寫建構函式,請注意在有些情況下也會以隱含方式呼叫該建構函式,且請務必確保能支援這些呼叫。從 Datastore 讀取實體時,系統會先呼叫不含引數的建構函式來建立空白實體,然後逐一設定金鑰和屬性值。當 get_or_insert() 或 get_or_insert_async() 建立新例項時,會將 **constructor_args 傳送給建構函式,然後再設定金鑰。
類別方法
- allocate_ids(size=None, max=None, parent=None, **ctx_options)
-
為這個模型類別分配一系列金鑰 ID。
引數
- size
- 要分配的 ID 數量。您可以選擇指定
size或max,但不能兩者同時指定。 - max
- 要分配的 ID 上限。您可以選擇指定
size或max,但不能兩者同時指定。 - parent
- 要分配 ID 的父項鍵。
- **ctx_options
- 脈絡選項
傳回已分配範圍的 (開始、結束) 元組,包含開始和結束值。
應用程式無法在交易中呼叫
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。如未指定,系統會取得目前應用程式的資料。
- 命名空間
- 命名空間。如果未指定,會取得預設命名空間的資料。
- 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)
-
distinct關鍵字引數為 group_by = projection 的簡寫。所有其他關鍵字引數都會傳遞至 Query 建構函式。如果指定了位置引數,會使用這些引數來設定初始篩選器。
傳回
Query物件。
實例方法
- populate(**constructor_options)
-
設定實體的屬性值。實體的關鍵字引數會自動辨識屬性名稱,所用的方式與建構函式相同。
- put(**ctx_options)
-
將實體的資料寫入 Datastore。傳回實體的金鑰。
引數
- **ctx_options
- 脈絡選項
- put_async(**ctx_options)
-
將實體的資料非同步寫入 Datastore。傳回
Future物件。Future物件的結果便是實體的 Key。引數
- **ctx_options
- 脈絡選項
- to_dict(include=all, exclude=None)
-
傳回包含模型屬性值的
dict。StructuredProperty和LocalStructuredProperty的屬性值會遞迴轉換為字典。引數:
- include
- 要納入的選用屬性清單。預設值:全部。
- exclude
- 要排除的屬性清單 (選用)。如果「納入」和「排除」之間有重疊部分,則「排除」會「勝出」。
注意:如果屬性值是可變動的物件 (例如代表重複屬性的清單,或是儲存在
JsonProperty中的字典或清單),除非明確轉換值 (例如StructuredProperty),否則系統會在儲存在實體中的字典傳回相同物件。在這類情況下,修改字典便會修改實體,反之亦然。
例項資料
- key
- 用於儲存模型鍵的特殊屬性。
掛鉤方法
應用程式的 Model 子類別可以將一或多個方法定義為作業前或作業後的「掛鉤」方法。舉例來說,如要在每次「get」之前執行特定程式碼,請定義模型子類別的 _pre_get_hook() 方法。如需編寫 Hook 函式的建議,請參閱「模型 Hook」。
- @classmethod
_pre_allocate_ids_hook(cls, size, max, parent) - 在以下項目之前執行的掛鉤:
allocate_ids() - @classmethod
_post_allocate_ids_hook(cls, size, max, parent, future) - Hook that runs after
allocate_ids() - @classmethod
_pre_delete_hook(cls, key) - 在以下項目之前執行的掛鉤:
delete() - @classmethod
_post_delete_hook(cls, key, future) - Hook that runs after
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)
- Hook that runs after
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()。也就是說,如果您一律使用 _ 開頭的方法,就能使用與方法名稱衝突的屬性名稱。不過請注意,您無法在建構函式中指定任何名為 key、parent 或 id 的屬性。
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.
如要建立能與任何模型互動的第三方資料庫,建議您使用以 _ 開頭的方法。