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() 傳回的值為金鑰,之後可用來擷取同一個實體:

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。如要寫入 Datastore,必須透過明確呼叫 put() 來寫入。

引數:

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

key
此模型的金鑰例項。如果使用 key 參數,idparent 必須為 None (預設值)。
ID
此模型的金鑰 ID。如果使用 id,金鑰必須為 None (預設值)。
parent
父項模型的金鑰項目。如為頂層模型,則為 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
父系實體金鑰 (如有)。
app
應用程式的 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 金鑰的特殊屬性。

掛鉤方法

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

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

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Python 2 適用的 App Engine 標準環境