實體屬性參考資料

Cloud Datastore 支援屬性值的各種資料類型。這些資料類型列舉如下:

  • 整數
  • 浮點數
  • 字串
  • 日期
  • 二進位資料

如需這些類型的完整清單,請參閱屬性和值類型

屬性和值類型

與實體相關聯的資料值由一或多個「屬性」組成。 每個屬性都有一個名稱及一或多個值。一個屬性可能會有多個類型的值,而兩個實體的相同屬性可能會有不同類型的值。屬性可能已建立索引或未建立索引 (排序或篩選屬性「P」的查詢將忽略「P」未建立索引的實體)。一個實體最多可有 20,000 個已建立索引的屬性。

支援的值類型如下:

當查詢的屬性具有混和類型的值時,Cloud Datastore 會根據內部表示法來決定排序:

  1. 空值
  2. 固定點數
    • 整數
    • 日期和時間
  3. 布林值
  4. 位元組序列
    • Unicode 字串
    • Blobstore 索引鍵
  5. 浮點數
  6. Cloud Datastore 金鑰

長文字字串和長位元組字串不會建立索引,因此未定義排序。

屬性類型

NDB 支援以下屬性類型:

屬性類型 說明
IntegerProperty 64 位元帶正負號整數
FloatProperty 雙精確度浮點數
BooleanProperty 布林值
StringProperty Unicode 字串;最多可為 1500 個位元組,會建立索引
TextProperty Unicode 字串;無長度限制,不會建立索引
BlobProperty 未解譯的位元組字串:
如果設定 indexed=True,則最多可為 1500 個位元組,會建立索引;
如果 indexedFalse (預設),則無長度限制,不會建立索引。
選用的關鍵字引數:compressed
DateTimeProperty 日期和時間 (請參閱日期和時間屬性)
DateProperty 日期 (請參閱日期和時間屬性)
TimeProperty 時間 (請參閱日期和時間屬性)
GeoPtProperty 地理位置。此為 ndb.GeoPt 物件。這個物件具有屬性 latlon,兩者皆為浮點數。您可以兩個浮點數建構此物件,例如 ndb.GeoPt(52.37, 4.88),或以字串 ndb.GeoPt("52.37, 4.88") 建構(這實際上跟 db.GeoPt 為相同類別)
KeyProperty Cloud Datastore 金鑰
選用的關鍵字引數:kind=kind,要求指派至這個屬性的金鑰一律設為指定的種類。可為字串或 Model 子類別。
BlobKeyProperty Blobstore 金鑰
對應至舊版 db API 中的 BlobReferenceProperty,但屬性值為 BlobKey 而非 BlobInfo;您可以使用 BlobInfo(blobkey) 從中建構 BlobInfo
UserProperty 使用者物件。
StructuredProperty 在一個模型種類中包含另一個模型種類,依值列出 (請參閱結構化屬性)
LocalStructuredProperty 類似 StructuredProperty,但在磁碟上會顯示為不透明 blob,不會建立索引 (請參閱結構化屬性)。
選用的關鍵字引數:compressed
JsonProperty 值為可使用 Python 的 json 模組序列化的 Python 物件 (例如,清單或字典或字串);Cloud Datastore 會將 JSON 序列化作業儲存為 blob。預設不會建立索引。
選用的關鍵字引數:compressed
PickleProperty 值為可使用 Python 的 pickle 通訊協定序列化的 Python 物件 (例如,清單或字典或字串);Cloud Datastore 會將 pickle 序列化作業儲存為 blob。預設不會建立索引。
選用的關鍵字引數:compressed
GenericProperty 一般值
大多用於 Expando 類別,但也可直接使用。其類型可能為:intlongfloatboolstrunicodedatetimeKeyBlobKeyGeoPtUserNone
ComputedProperty 透過使用者定義的函數從其他屬性運算得出其值 (請參閱運算屬性)。

這些屬性有部分具有選用的關鍵字引數 compressed。如果屬性具有 compressed=True,則其磁碟上的資料會以 gzip 壓縮。這樣佔用空間較少,但寫入和讀取作業需要 CPU 加密/解密。

壓縮和解壓縮都是屬於「消極」作業;壓縮的屬性值只會在您初次存取時解壓縮。如果在沒有存取壓縮屬性的情況下讀取並寫回包含壓縮屬性值的實體,將不會進行任何解壓縮和壓縮作業。在這種消極結構定義下也會進行內容快取,但 Memcache 一律會儲存壓縮屬性的壓縮值。

壓縮作業需要額外的 CPU 作業時間,因此最佳做法是:只有在資料因未經壓縮而過大時才使用壓縮屬性。請記住,gzip 壓縮作業通常無法用於圖片和其他媒體資料,這是因為這些格式已使用媒體專屬的壓縮演算法進行壓縮 (例如,圖片使用 JPEG)。

屬性選項

大部分屬性類型支援特定標準引數。首先是選用的位置引數,用於指定屬性的 Cloud Datastore 名稱。透過這個引數,您可以從應用程式的觀點為屬性提供與 Cloud Datastore 不同的名稱。這個引數常用於減少在 Cloud Datastore 的佔用空間,讓 Cloud Datastore 採用簡略的屬性名稱,而程式碼則採用較長且較具意義的名稱。例如:

class Employee(ndb.Model):
    full_name = ndb.StringProperty('n')
    retirement_age = ndb.IntegerProperty('r')

這特別適合用於重複屬性的情況,因為每個實體預期會有多個值。

此外,大部分屬性類型支援下列關鍵字引數:

引數 類型 預設 說明
indexed bool 通常為 True 包含 Cloud Datastore 索引中的屬性;如果為 False,值將無法查詢,但寫入速度會加快。並非所有屬性類型都支援索引;為這些類型設定 indexedTrue 時會發生失敗。
相較於建立索引的屬性,不建立索引的屬性需要的寫入作業較少。
repeated bool False 屬性值為包含基本類型值的 Python 清單 (請參閱重複屬性)。
無法與 required=Truedefault=True 合併使用。
required bool False 屬性必須有指定值。
default 屬性的基本類型 未明確指定時的預設屬性值。
choices 基本類型的值清單 None 選用的允許值清單。
validator 函式 None

用於驗證並且可能還會強制轉換該值的選用函式。

搭配引數 (prop, value) 一起呼叫,應傳回 (可能經過強制轉換的) 值或引發例外狀況。對強制轉換的值再次呼叫函式,並不會再進一步修改該值 (舉例來說,可傳回 value.strip()value.lower(),但不可傳回 value + '$')。另外也可能傳回 None,表示「沒有變更」。另請參閱寫入屬性子類別

verbose_name 字串None

用於網路表單架構的選用 HTML 標籤,例如 jinja2。

重複屬性

具有 repeated=True 的任何屬性即為「重複屬性」。這個屬性採用基本類型的值清單,而非單一值。例如,以 IntegerProperty(repeated=True) 定義的屬性值為整數清單。

在 Cloud Datastore 中,這類屬性可能會有多個值。每個值都會建立個別的索引記錄。這會影響查詢語意;範例請見查詢重複屬性

下列範例使用重複屬性:

class Article(ndb.Model):
    title = ndb.StringProperty()
    stars = ndb.IntegerProperty()
    tags = ndb.StringProperty(repeated=True)
...
article = Article(
    title='Python versus Ruby',
    stars=3,
    tags=['python', 'ruby'])
article.put()

這會建立具有下列內容的 Cloud Datastore 實體:

assert article.title == 'Python versus Ruby'
assert article.stars == 3
assert sorted(article.tags) == sorted(['python', 'ruby'])

查詢 tags 屬性時,此實體將符合 'python''ruby' 的查詢。

在更新重複屬性時,您可以為其指派新的清單,或修改目前使用的現有清單。如果指派新的清單,系統會立即驗證清單項目的類型。無效的項目類型 (例如,為上述的 art.tags 指派 [1, 2]) 會引發例外狀況。如果修改清單,系統並不會立即驗證變更,而是會在將實體寫入至 Cloud Datastore 時驗證其值。

Cloud Datastore 會保留重複屬性中的清單項目順序,因此您可以為排序方式賦予意義。

日期和時間屬性

用於儲存日期與時間相關值的屬性類型有三種:

  • DateProperty
  • TimeProperty
  • DateTimeProperty

這些類型採用標準 Python datetime 模組的對應類別 (datetimedatetime) 的值。三者之中最常見的是 DateTimeProperty,同時表示日曆日期與一天中的時間;另外兩者通常適用於只需要日期 (例如出生日期) 或只需要時間 (例如會議時間) 的特殊用途。基於技術上的原因,DatePropertyTimePropertyDateTimeProperty 的子類別,但您不應該依賴這個繼承關係 (請注意,這和 datetime 模組本身定義的基本類別之間的繼承關係不同)。

注意:App Engine 時鐘時間一律以世界標準時間 (UTC) 表示。如果您使用目前日期或時間 (datetime.datetime.now()) 作為其值,或在 datetime 物件和 POSIX 時間戳記或時間元組之間轉換,這點會很重要。不過,Cloud Datastore 不會儲存任何明確的時區資訊,所以只要您在使用目前的時間或進行時間轉換時小心謹慎,便可使用這些項目來表示任何時區的當地時間。

這些屬性各有兩個額外的布林值關鍵字選項:

選項 說明
auto_now_add 將屬性設為實體建立時的日期/時間。您可以手動覆寫這個屬性。在實體更新時,屬性不會變更。如要變更,請使用 auto_now
auto_now 將屬性設為實體建立及更新時的日期/時間。

這些選項無法與 repeated=True 合併使用。兩個選項預設皆為 False;如果皆設為 True,將以 auto_now 為優先。您可以覆寫 auto_now_add=True 的屬性值,但無法覆寫 auto_now=True 的屬性值。除非寫入實體,否則不會自動產生其值;也就是說,這些選項不會提供動態預設值 (這些細節與舊版 db API 不同)。

附註:如果交易在寫入具備 auto_now_add=True 的屬性時失敗並在之後重試,該交易會使用與初次嘗試時相同的時間值,而不會更新為重試的時間。如果交易永久失敗,仍會在實體的記憶體複本中設定屬性值。

結構化屬性

您可以結構化模型屬性。舉例來說,您可以定義模型類別 Contact 來包含具備內部結構的地址清單。 「結構化屬性」(類型 StructuredProperty) 可讓您進行此操作;例如:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
guido = Contact(
    name='Guido',
    addresses=[
        Address(
            type='home',
            city='Amsterdam'),
        Address(
            type='work',
            street='Spear St',
            city='SF')])

guido.put()

這會建立具有下列屬性的單一 Cloud Datastore 實體:

assert guido.name == 'Guido'
addresses = guido.addresses
assert addresses[0].type == 'home'
assert addresses[1].type == 'work'
assert addresses[0].street is None
assert addresses[1].street == 'Spear St'
assert addresses[0].city == 'Amsterdam'
assert addresses[1].city == 'SF'

讀回這類實體將重新建構與原本完全相同的 Contact 實體。雖然 Address 執行個體是使用與模型類別相同的語法定義,但這些執行個體並非完善的實體。這些實體在 Cloud Datastore 中並無各自的金鑰,也無法脫離所屬的 Contact 實體單獨擷取。但是,應用程式可以查詢個別欄位的值;請參閱篩選結構化屬性值。請注意,Cloud Datastore 會將 address.typeaddress.streetaddress.city 視為平行陣列,但 NDB 程式庫會隱藏這個面向,並且建構對應的 Address 執行個體清單。

您可以為結構化屬性指定常用的屬性選項 (indexed 除外)。在此案例中,Cloud Datastore 的名稱是「第二個」位置引數 (第一個是用於定義子結構的模型類別)。

當您不需要查詢子結構的內部屬性時,您就可以改為使用本機的結構化屬性 (LocalStructuredProperty)。如果您在上述範例中將 StructuredProperty 取代為 LocalStructuredProperty,Python 程式碼會有相同的行為,但 Cloud Datastore 僅會在各個地址看到不透明 blob。範例建立的 guido 實體會儲存為: name = 'Guido' address = <{'type': 'home', 'city': 'Amsterdam'} 的不透明 blob> address = <{'type': 'work', 'city': 'SF', 'street': 'Spear St'} 的不透明 blob>

這個實體可正確讀回。由於這種類型的屬性一律不會建立索引,所以您無法查詢地址值。

附註:具有巢狀結構屬性的 StructuredProperty (無論是否為結構化屬性) 僅支援單層的重複屬性。StructuredProperty 或巢狀結構屬性皆可重複,但無法兩者同時重複。這種情況的因應措施是使用 LocalStructuredProperty,如此就不會有上述限制 (但無法允許查詢其屬性值)。

運算屬性

「運算屬性」 (ComputedProperty) 屬於唯讀屬性,其值是以應用程式提供的函式運算其他屬性值所得出。請注意,運算屬性僅支援一般屬性支援的類型!運算值會寫入 Cloud Datastore 以方便查詢,並且在 Cloud Datastore 檢視器中顯示,但是從 Cloud Datastore 讀回實體時會忽略儲存的值;事實上,每次要求該值時,都會呼叫函式來重新運算其值。例如:

class SomeEntity(ndb.Model):
    name = ndb.StringProperty()
    name_lower = ndb.ComputedProperty(lambda self: self.name.lower())
...
entity = SomeEntity(name='Nick')
entity.put()

這會儲存具有下列屬性值的實體:

assert entity.name == 'Nick'
assert entity.name_lower == 'nick'

如果我們將名稱變更為「Nickie」並要求 name_lower 的值,系統會傳回「nickie」:

entity.name = 'Nick'
assert entity.name_lower == 'nick'
entity.name = 'Nickie'
assert entity.name_lower == 'nickie'

附註:如果應用程式查詢運算值,請使用 ComputedProperty。如果您只是要以 Python 程式碼使用衍生的版本,請定義一般方法或使用 Python 內建的 @property

附註:如果您不是手動指定金鑰來建立模型,而是依賴 Cloud Datastore 自動產生實體的 ID,則在第一個 put() 中,ComputedProperty 將無法讀取 ID 欄位,因為需要先運算欄位才會產生 ID。如果您需要使用實體 ID 的 ComputedProperty,您可以使用 allocate_ids 方法產生建立實體所需的 ID 與金鑰,如此 ComputedProperty 便可在實體的第一個 put() 中參照該 ID。

Google Protocol RPC 訊息屬性

Google Protocol RPC 程式庫採用結構化資料的 Message 物件;它們可能代表 RPC 要求、回應或其他項目。NDB 提供的 API 可將 Google Protocol RPC Message 物件儲存為實體屬性。假設您定義一個 Message 子類別:

from protorpc import messages
...
class Note(messages.Message):
    text = messages.StringField(1, required=True)
    when = messages.IntegerField(2)

您可以使用 NDB 的 msgprop API,將 Cloud Datastore 中的 Note 物件儲存為實體屬性值。

from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
...
class NoteStore(ndb.Model):
    note = msgprop.MessageProperty(Note, indexed_fields=['when'])
    name = ndb.StringProperty()
...
my_note = Note(text='Excellent note', when=50)

ns = NoteStore(note=my_note, name='excellent')
key = ns.put()

new_notes = NoteStore.query(NoteStore.note.when >= 10).fetch()

如要查詢欄位名稱,您必須建立這些欄位名稱的索引。您可以將 indexed_fields 參數設為 MessageProperty,指定要建立索引的欄位名稱清單。

MessageProperty 支援許多 (但非全部) 屬性選項。支援項目如下:

  • name
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

訊息屬性不支援 indexed 屬性選項;您無法建立 Message 值的索引 (您可以依照前述操作建立訊息欄位的索引)。

巢狀結構訊息 (使用 MessageField) 同樣適用:

class Notebook(messages.Message):
    notes = messages.MessageField(Note, 1, repeated=True)
...
class SignedStorableNotebook(ndb.Model):
    author = ndb.StringProperty()
    nb = msgprop.MessageProperty(
        Notebook, indexed_fields=['notes.text', 'notes.when'])

MessageProperty 具有特殊屬性選項 protocol,指定訊息物件透過何種方式序列化至 Cloud Datastore。其值為 protorpc.remote.Protocols 類別使用的通訊協定名稱。支援的通訊協定名稱為 protobufprotojson;預設為 protobuf

msgprop 也可定義 EnumProperty,這個屬性類型可用於在實體中儲存 protorpc.messages.Enum 值。範例:

class Color(messages.Enum):
    RED = 620
    GREEN = 495
    BLUE = 450
...
class Part(ndb.Model):
    name = ndb.StringProperty()
    color = msgprop.EnumProperty(Color, required=True)
...
p1 = Part(name='foo', color=Color.RED)
print p1.color  # prints "RED"

EnumProperty 會以整數形式儲存其值;事實上,EnumPropertyIntegerProperty 的子類別。這代表您可以重新命名 enum 值而無需修改已儲存的實體,但無法為其重新編號。

EnumProperty 支援下列屬性選項

  • name
  • indexed
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

關於 NDB 實體模型

NDB 實體模型可定義「屬性」。實體屬性有點類似 Python 類別的資料成員,屬於儲存資料的結構化方法;此外,實體屬性也有點類似資料庫結構定義中的欄位。

一般應用程式在定義資料模型時,會定義繼承自 Model 的類別,且該類別會具有特定屬性 (property) 類別的屬性 (attribute)。例如:


from google.appengine.ext import ndb
...
class Account(ndb.Model):
    username = ndb.StringProperty()
    userid = ndb.IntegerProperty()
    email = ndb.StringProperty()

上列的 usernameuseridemail 都是 Account 的屬性。

另外還有其他屬性類型。有些適合用來表示日期和時間,並且具有自動更新的便利功能。

應用程式可指定屬性的選項來調整屬性的行為;這可簡化驗證、設定預設值,或變更查詢索引作業。

模型可能還有更複雜的屬性:重複屬性類似於清單;結構化屬性類似於物件;唯讀的運算屬性則是透過函式定義;您可以使用其他一或多個屬性,輕鬆為某個屬性進行定義。 Expando 模型則可動態定義屬性。

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

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

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