模型類別

附註:我們強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,因為 NDB 用戶端程式庫與本用戶端程式庫相較之下有幾個優點,例如能透過 Memcache API 自動將實體加入快取。如果您目前使用的是舊版的 DB 用戶端程式庫,請參閱從 DB 至 NDB 的遷移指南

Model 類別是資料模型定義的父類別。

Model 應在 google.appengine.ext.db 模組中定義。

簡介

應用程式定義資料模型的方式,是定義將 Model 當做子類別的類別。模型屬性是以類別屬性及 Property 類別例項進行定義。例如:

class Story(db.Model):
  title = db.StringProperty()
  body = db.TextProperty()
  created = db.DateTimeProperty(auto_now_add=True)

應用程式將 Model 類別的子類別例項化,以建立新的資料實體。實體屬性可利用例項屬性或關鍵字引數指派至建構函式。

s = Story()
s.title = "The Three Little Pigs"

s = Story(title="The Three Little Pigs")

模型子類別名稱會當做 Datastore 實體種類名稱使用。Datastore 保留所有以兩條底線 (__) 開頭的種類名稱,因此模型子類別不得使用這類名稱。

屬性名稱將做為實體對應屬性的名稱。模型執行個體屬性名稱若以底線 (_) 開頭將遭到忽略,因此應用程式可利用這類屬性,將資料儲存在並未儲存於 Datastore 的模型執行個體。

Datastore 及模型類別 API 針對屬性名稱及模型執行個體屬性施加多項限制。請參閱不允許使用的屬性名稱瞭解完整說明。

每個實體都有「金鑰,是代表實體的唯一 ID。金鑰可能包含選用的「金鑰名稱」,是特定種類實體之間的唯一字串。實體種類及金鑰名稱可搭配使用 Key.from_path()Model.get_by_key_name() 方法,以擷取實體。

實體也可能擁有選用的「父項實體。父項子項關係形成「實體群組,用於控制 Datastore 之中的交易能力及資料局部性。應用程式在兩個實體之間建立父項子項關係的方式,是將父系實體傳送至子系實體的建構函式,作為 parent 引數。

方法 Model.get_or_insert() 可用於擷取可能不存在的實體,於必要時在 Datastore 之中建立:

keyname = "some_key"
s = Story.get_or_insert(keyname, title="The Three Little Pigs")

附註:模型執行個體在 Datastore 之中並沒有對應實體,直到明確或透過 Model.get_or_insert() 首次寫入 (put) 為止。

如需建立屬於模型執行個體資料副本的 dict,請使用 db.to_dict 函式。

建構函式

Model 類別的建構函式定義如下:

class Model (parent=None, key_name=None, **kwds)

資料模型定義的父類別。

建構期間將呼叫每項屬性的 validate() 方法。前述呼叫的例外狀況將傳播至此建構函式的呼叫者。

引數

parent
模型執行個體或實體 (為新實體的父項) 金鑰。
key_name

實體的金鑰名稱。這個名稱會成為主要金鑰的一部分。如果值為 None,就會使用系統產生的數字 ID 做為金鑰。

key_name 的值不得為 __*__ 形式。

金鑰名稱會以 Unicode 字串形式儲存,其中的 str 值會轉換成 ASCII 文字。

在此物件呼叫 put() 將「覆寫」具有相同金鑰的任何現有 Datastore 實體。

kwds
例項屬性的初始值,形式為關鍵字引數。每項名稱會對應模型類別定義的屬性。

其他關鍵字引數

key

實體明確的 Key 執行個體。無法與 key_nameparent 搭配使用。如果值為 None,將回到 key_nameparent 行為。使用 allocate_ids() 保留新實體數字 ID 時相當實用。

key 的值必須為有效的 Key 執行個體。

在此物件呼叫 put() 將「覆寫」具有相同金鑰的任何現有 Datastore 實體。

類別方法

Model 類別具有下列類別方法:

Model.get (keys)

針對特定金鑰 (或多個金鑰) 擷取模型執行個體 (或多個執行個體)。 金鑰必須代表模型種類實體。如果提供的金鑰並非屬於正確種類,系統就會傳回 KindError 例外狀況。

此方法類似於 db.get() 函式,且包含額外的類型檢查。

引數

keys
要擷取的實體金鑰、金鑰的字串表示法,或是金鑰或金鑰字串表示法的清單。
read_policy
指定所需資料一致性程度的讀取政策:
STRONG_CONSISTENCY
保證為最新結果,但僅限單一實體群組
EVENTUAL_CONSISTENCY
可涵蓋多個實體群組,但可能偶爾會傳回過時結果。一般來說,最終一致性查詢的執行速度,比同步一致性查詢更快,但並不保證絕對如此。

注意:全域 (非祖系) 查詢會忽略這個引數。

deadline
在因錯誤而取消之前,等待 Datastore 傳回結果的秒數上限,可接受整數或浮點值。不得高於預設值 (60 秒),但可向下調整來確保特定作業快速失敗 (例如更快將回應傳回給使用者、重試作業、嘗試不同作業,或是將作業新增至工作佇列)。

如果 keys 包含單一金鑰 (或其字串表示法),這個方法會在該金鑰存在於 Datastore 時傳回與金鑰相關的模型執行個體,否則會傳回 None。如果 keys 為清單,傳回值為對應的模型執行個體清單,如果指定金鑰沒有實體,則為 None 值。

另請參閱 db.get() 函式。

Model.get_by_id (ids, parent=None)

擷取模型執行個體 (或多個執行個體) 用於特定數字 ID (或多個數字 ID)。

引數

ids
數字實體 ID,或數字 ID 清單。
parent
要求實體的父系實體,為模型或金鑰形式,如果要求實體沒有父項,則為 None (預設值)。以單一呼叫要求的多個實體,必須同屬一個父項。
read_policy
指定所需資料一致性程度的讀取政策:
STRONG_CONSISTENCY
保證為最新結果,但僅限單一實體群組
EVENTUAL_CONSISTENCY
可涵蓋多個實體群組,但可能偶爾會傳回過時結果。一般來說,最終一致性查詢的執行速度,比同步一致性查詢更快,但並不保證絕對如此。

注意:全域 (非祖系) 查詢會忽略這個引數。

deadline
在因錯誤而取消之前,等待 Datastore 傳回結果的秒數上限,可接受整數或浮點值。不得高於預設值 (60 秒),但可向下調整來確保特定作業快速失敗 (例如更快將回應傳回給使用者、重試作業、嘗試不同作業,或是將作業新增至工作佇列)。

如果 ids 包含單一數字 ID,這個方法會在該 ID 存在於 Datastore 時傳回與 ID 相關的模型執行個體,否則會傳回 None。如果 ids 為清單,傳回值為對應的模型執行個體清單,如果指定數字 ID 沒有實體,則為 None 值。

Model.get_by_key_name (key_names, parent=None)

擷取模型執行個體 (或多個執行個體) 用於特定金鑰名稱 (或多個名稱)。

引數

key_names
金鑰名稱或金鑰名稱清單。
parent
要求實體的父系實體,為模型執行個體或金鑰形式,如果要求實體沒有父項,則為 None (預設值)。以單一呼叫要求的多個實體,必須同屬一個父項。
read_policy
指定所需資料一致性程度的讀取政策:
STRONG_CONSISTENCY
保證為最新結果,但僅限單一實體群組
EVENTUAL_CONSISTENCY
可涵蓋多個實體群組,但可能偶爾會傳回過時結果。一般來說,最終一致性查詢的執行速度,比同步一致性查詢更快,但並不保證絕對如此。

注意:全域 (非祖系) 查詢會忽略這個引數。

deadline
在因錯誤而取消之前,等待 Datastore 傳回結果的秒數上限,可接受整數或浮點值。不得高於預設值 (60 秒),但可向下調整來確保特定作業快速失敗 (例如更快將回應傳回給使用者、重試作業、嘗試不同作業,或是將作業新增至工作佇列)。

如果 key_names 包含單一金鑰名稱,這個方法會在該名稱存在於 Datastore 時傳回與名稱相關的模型執行個體,否則會傳回 None。如果 key_names 為清單,傳回值為對應的模型執行個體清單,如果指定金鑰名稱沒有實體,則為 None 值。

Model.get_or_insert (key_name, **kwds)

嘗試以指定金鑰名稱取得模型種類的實體。如果存在,get_or_insert() 會直接將其傳回;如果不存在,則會在 kwds 中建立、儲存及傳回具有指定種類、名稱和參數的新實體。

Get 及之後 (可能) 的 put 運算將納入交易之中,以確保不可部分完成性。這代表 get_or_insert() 絕對不會覆寫現有實體,只有在沒有指定種類及名稱的實體存在時,才會插入新的實體。換句話說,get_or_insert() 與下列 Python 程式碼的功能相同:

def txn(key_name, **kwds):
  entity = Story.get_by_key_name(key_name, parent=kwds.get('parent'))
  if entity is None:
    entity = Story(key_name=key_name, **kwds)
    entity.put()
  return entity

def get_or_insert(key_name, **kwargs):
  return db.run_in_transaction(txn, key_name, **kwargs)

get_or_insert('some key', title="The Three Little Pigs")

引數

key_name
這是實體金鑰的名稱
kwds
具有指定金鑰名稱的執行個體不存在時,傳送至模型類別建構函式的關鍵字引數。如果所需的實體具有父項,就需要 parent 引數。

附註:get_or_insert() 不接受 read_policydeadline 引數。

方法傳回代表要求實體的模型類別執行個體,不論是否存在或由方法建立。與所有 Datastore 運算一樣,若交易無法完成,此方法可提出 TransactionFailedError

Model.all (keys_only=False)

傳回 Query 物件,代表對應至此模型種類的所有實體。查詢物件的方法可於執行查詢前,在查詢套用篩選器及排序順序;詳情請參閱 Query 類別頁面

引數

keys_only
查詢應傳回完整實體或是僅傳回金鑰。相較於傳回完整實體的查詢,傳回金鑰的查詢速度較快,使用的 CPU 時間較短
Model.gql (query_string, *args, **kwds)

針對此模型執行個體執行 GQL 查詢。

引數

query_string
GQL 查詢在 SELECT * FROM model 之後的部分 (使用此類別方法時一定包含在內)。
args
位置參數繫結,類似於 GqlQuery() 建構函式
kwds
關鍵字參數係結,類似於 GqlQuery()建構函式
s = Story.gql("WHERE title = :1", "Little Red Riding Hood")

s = Story.gql("WHERE title = :title", title="Little Red Riding Hood")

傳回值為 GqlQuery 物件,可用於存取結果。

Model.kind ()
傳回模型的種類,通常是 Model 子類別的名稱。
Model.properties ()
傳回為這個模型類別定義的所有屬性字典。

執行個體方法

模型執行個體的方法如下:

key ()

傳回此模型執行個體的 Datastore Key

模型執行個體金鑰包含執行個體的「實體種類,以及不重複的唯一「ID」。ID 可能是「金鑰名稱」字串 (於執行個體建立時由應用程式明確指派),或是整數「數字 ID」 (於執行個體寫入 (put) 至 Datastore 時由 App Engine 自動指派)。如果在執行個體獲指派 ID 之前呼叫 key(),系統會傳回 NotSavedError 例外狀況。

put ()

將模型執行個體儲存於 Datastore。若模型執行個體為新建且從未儲存,此方法將於 Datastore 建立新的資料實體,否則將以目前屬性值更新資料實體。

方法傳回已儲存實體的金鑰。

若資料無法修訂,系統會傳回 TransactionFailedError 例外狀況。

引數

deadline
在因錯誤而取消之前,等待 Datastore 傳回結果的秒數上限,可接受整數或浮點值。不得高於預設值 (60 秒),但可向下調整,確保特定運算快速失敗 (例如更快速傳回回應給使用者、重試運算、嘗試不同運算,或新增運算至工作佇列)。
delete ()

從 Datastore 中刪除模型執行個體。如果執行個體從未寫入 (put) 至 Datastore,則刪除會提出 NotSavedError 例外狀況。

引數

deadline
在因錯誤而取消之前,等待 Datastore 傳回結果的秒數上限,可接受整數或浮點值。不得高於預設值 (60 秒),但可向下調整,確保特定運算快速失敗 (例如更快速傳回回應給使用者、重試運算、嘗試不同運算,或新增運算至工作佇列)。
is_saved ()

如果模型執行個體已寫入 (put) 至 Datastore 至少一次,將傳回 True

此方法僅檢查執行個體自建立後,是否曾寫入至 Datastore 至少一次,並不會檢查執行個體屬性自上次寫入後是否曾經更新。

dynamic_properties ()

傳回為此模型執行個體定義的動態屬性名稱完整清單。這僅適用於 Expando 類別的執行個體。若為非 Expando 模型執行個體,只會傳回空白清單。

parent ()

傳回此執行個體父系實體的模型執行個體;如果此執行個體沒有父項,則傳回 None

parent_key ()

傳回此執行個體父系實體的 Key,如果此執行個體沒有父項,則傳回 None

to_xml ()

傳回模型執行個體的 XML 表示法。

符合 AtomData 規格的屬性值。

不允許的屬性名稱

Datastore 及其 API 對實體屬性名稱及模型執行個體屬性施加多項限制。

Datastore 會保留以兩個底線 (__*__) 為開頭和結尾的所有屬性名稱。Datastore 實體的屬性不可具有此類名稱。

如果 ModelExpando 類別的開頭為底線 (_),Python 模型 API 就會忽略當中的所有屬性。您的應用程式可利用這類屬性,在資料與未儲存至 Datastore 的模型物件之間建立關聯。

最後 Python 模型 API 會使用物件屬性定義模型屬性,而根據預設,Datastore 實體屬性會以物件屬性命名。由於 Model 類別具有多項屬性及方法用於其他用途,因此前述屬性無法用於 Python API 之中的屬性。例如,Model 無法擁有以屬性 key 存取的屬性。

不過,屬性可為屬性建構函式提供 name 引數,為 Datastore 指派與屬性名稱不同的名稱。這樣可讓 Datastore 實體的屬性名稱類似於 Model 類別之中保留的屬性,並於類別中使用不同的屬性名稱。

class MyModel(db.Model):
  obj_key = db.StringProperty(name="key")

Python API 的 Model 類別保留下列屬性名稱:

  • all
  • app
  • copy
  • delete
  • entity
  • entity_type
  • fields
  • from_entity
  • get
  • gql
  • instance_properties
  • is_saved
  • key
  • key_name
  • kind
  • parent
  • parent_key
  • properties
  • put
  • setdefault
  • to_xml
  • update