NDB 模型類別

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

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
這個模型的金鑰 ID。如果使用 id,金鑰必須為 None (預設值)。
parent
父項模型的金鑰項目。如為頂層模型,則為 None。如果使用 parentkey 必須為 None
命名空間
該實體使用的命名空間。如要使用現有的命名空間,則為 None (預設值)。 如果使用 namespacekey 必須為 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 數量。您可以選擇指定 sizemax,但不能兩者同時指定。
max
要分配的 ID 上限。您可以選擇指定 sizemax,但不能兩者同時指定。
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)

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

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)

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

引數:

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()。也就是說,如果您一律使用 _ 開頭的方法,就能使用與方法名稱衝突的屬性名稱。不過請注意,您無法在建構函式中指定任何名為 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.

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