繼承自 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()
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
- 此模型的 Key ID。如果使用
id
,鍵必須為None
(預設值)。 - parent 父項模型的
- Key 例項,或頂層模型的
None
。如果使用parent
,key
必須為None
。 - namespace
- 命名空間 (該實體使用的命名空間),或
None
(預設值) (使用目前的命名空間)。如果使用namespace
,key
必須為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 數量。您可以選擇指定
size
或max
,但不能兩者同時指定。 - max
- 要分配的 ID 數量上限。您可以選擇指定
size
或max
,但不能兩者同時指定。 - 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)
-
關鍵字引數
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)
-
傳回包含模型屬性值的
dict
。StructuredProperty
和LocalStructuredProperty
的屬性值會以遞迴方式轉換為字典。引數:
- include
- 選用要納入的屬性清單。預設值:全部。
- exclude
- 選用的排除屬性清單。如果include 和exclude 之間有重疊部分,則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) 取得這個模型的實體時,在 - 掛鉤。
- @classmethod
_post_get_hook(cls, key, future) 取得這個模型的實體時,在 - _pre_put_hook(self)
- 在
put()
之前執行的掛鉤 - _post_put_hook(self, future)
- 在
put()
之後執行的掛鉤
Key.get()
之前執行的 Key.get()
之後執行的掛鉤。自我檢查
您可以使用這些方法檢查特定模型的屬性和設定。如果您要編寫可接受多種模型類型的程式庫或函式,這項功能就非常實用。
依種類查詢
每個模型都具有「類型」。除非遭到覆寫,否則類型通常與類別名稱相同。您可以使用 _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.
如要建立能與任何模型互動的第三方資料庫,建議您使用以 _
開頭的方法。