Google Code が利用できる言語: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
データストア エンティティにはキーとプロパティ セットが含まれます。アプリケーションは Datastore API を使用してデータ モデルを定義し、そのモデルのインスタンスを生成してエンティティとして格納します。モデルは API によって作成されたエンティティに共通の構成を提供し、プロパティ値を検証するための規則を定義することができます。
アプリケーションは、「モデル」を使用して、使用データの種類を記述します。モデルとは、Model クラスから継承する Python クラスです。このモデル クラスは、新しい種類のデータストア エンティティと、その種類に必要なプロパティを定義します。
モデル プロパティを定義する場合は、モデル クラスのクラス属性を使用します。各クラス属性は、Property クラスのサブクラスのインスタンスです。通常は提供されるプロパティ クラスのいずれかです。プロパティ インスタンスは、プロパティの設定(インスタンスを有効にするためにプロパティが必要かどうか、プロパティが指定されていない場合にインスタンスのデフォルト値を使用するかなど)を保持します。
from google.appengine.ext import db class Pet(db.Model): name = db.StringProperty(required=True) type = db.StringProperty(required=True, choices=set(["cat", "dog", "bird"])) birthdate = db.DateProperty() weight_in_pounds = db.IntegerProperty() spayed_or_neutered = db.BooleanProperty() owner = db.UserProperty(required=True)
エンティティの種類が定義されたエンティティは、対応するモデル クラスのインスタンスによって API で表現されます。アプリケーションが新しいエンティティを作成する場合は、クラスのコンストラクタを呼び出します。アプリケーションはインスタンスの属性を使用して、エンティティのプロパティにアクセスし、処理します。モデル インスタンスのコンストラクタは、プロパティの初期値をキーワード引数として受け入れます。
from google.appengine.api import users
pet = Pet(name="Fluffy",
type="cat",
owner=users.get_current_user())
pet.weight_in_pounds = 24
注: モデル 「クラス」の属性は、そのモデル プロパティの設定です。その値が Property インスタンスです。モデル 「インスタンス」の属性は、Property クラスによって受け入れられる値の種類の、実際のプロパティ値です。
この Model クラスは Property インスタンスを使用して、モデル インスタンスの属性に割り当てられた値を検証します。プロパティ値が検証されるのは、モデル インスタンスが最初に作成されるときと、インスタンス属性に新しい値が割り当てられるときです。これによって、プロパティが無効な値を持つことはなくなります。
検証はインスタンスが作成されるときに行われるので、必要に応じて設定されるプロパティはすべて、コンストラクタで初期化する必要があります。上記の例では、name、type、owner はすべて必須の値なので、コンストラクタでそれぞれの初期値が指定されています。weight_in_pounds は、このモデルでは必須の値ではないので、最初に割り当ては行わず、後で値が割り当てられています。
コンストラクタを使用して作成されたモデルのインスタンスは、最初に「プット」されるまではデータストアに存在しません。データの作成、取得、削除をご覧ください。
注: Python クラスの属性と同様、モデル プロパティの設定が初期化されるのは、スクリプトやモジュールが最初にインポートされるときです。App Engine は要求の合間にインポートされたモジュールをキャッシュするので、あるユーザーの要求時に初期化したモジュール設定を別のユーザーの要求時に再使用することができます。デフォルト値など、モデルのプロパティ設定は、要求や現在のユーザーに特有のデータを使用して初期化しないでください。詳細については、アプリケーション キャッシュをご覧ください。
Model クラスを使用して定義されたモデルは、クラスのすべてのインスタンスが必ず持っている一定のプロパティ セットを(たぶんデフォルト値で)設定しています。これはデータ オブジェクトをモデリングする便利な方法ですが、データストアでは、指定された種類のすべてのエンティティが同じプロパティ セットを持っている必要はありません。
エンティティのプロパティは、同じ種類の他のエンティティのプロパティと必ずしも同じでない方が便利な場合もあります。そのようなエンティティは「expando」モデルによって Datastore API で表現されます。Expando モデル クラスは、Expando スーパークラスのサブクラスを作成します。expando モデルのインスタンスの属性に割り当てられた値は、属性の名前を使用して、データストア エンティティのプロパティになります。このようなプロパティを「動的プロパティ」といいます。クラス属性内にある Property クラスのインスタンスを使用して定義されたプロパティは「固定プロパティ」です。
expando モデルは、固定プロパティと動的プロパティのどちらも持つことができます。このモデル クラスは、固定プロパティの Property 設定オブジェクトを使用して、クラス属性を設定します。アプリケーションが動的プロパティを作成するのは、それらに値を割り当てるときです。
class Person(db.Expando): first_name = db.StringProperty() last_name = db.StringProperty() hobbies = db.StringListProperty() p = Person(first_name="Albert", last_name="Johnson") p.hobbies = ["chess", "travel"] p.chess_elo_rating = 1350 p.travel_countries_visited = ["Spain", "Italy", "USA", "Brazil"] p.travel_trip_count = 13
動的プロパティは、モデル プロパティの定義を持たないので検証されません。動的プロパティには、データストアの基本型(None を含む)のどの値でも割り当てることができます。同じ種類の 2 つのエンティティは、同じ動的プロパティの異なる種類の値を持つことができます。一方のエンティティに設定したプロパティをもう一方のエンティティには設定しなくても構いません。
固定プロパティとは違い、動的プロパティは存在する必要はありません。None の値を持つ動的プロパティは、存在しない動的プロパティとは異なります。expando モデルのインスタンスにプロパティの属性がなければ、対応するデータ エンティティはそのプロパティを持ちません。動的プロパティは、その属性を削除することで削除できます。
del p.chess_elo_rating
フィルタに動的プロパティを使用するクエリは、そのプロパティの値がクエリで使用する値と同じ種類であるエンティティのみを返します。同様に、クエリはそのプロパティ セットを持つエンティティのみを返します。
p1 = Person()
p1.favorite = 42
p1.put()
p2 = Person()
p2.favorite = "blue"
p2.put()
p3 = Person()
p3.put()
people = db.GqlQuery("SELECT * FROM Person WHERE favorite < :1", 50)
# people has p1, but not p2 or p3
people = db.GqlQuery("SELECT * FROM Person WHERE favorite > :1", 50)
# people has no results
Expando クラスは Model クラスのサブクラスであり、そのメソッドのすべてを継承します。
Python API にはデータ モデリング用にもう 1 つのクラスがあり、クラスの階層の定義や、指定したクラスとすべてのサブクラスのエンティティを返すクエリを実行することができます。このようなモデルおよびクエリは「ポリモーフィック」と呼ばれます。これは、あるクラスのインスタンスを親クラスのクエリの結果とすることができるためです。
次の例では、Contact クラス、および Contact のサブクラスの Person と Company クラスを定義しています。
from google.appengine.ext import db from google.appengine.ext.db import polymodel class Contact(polymodel.PolyModel): phone_number = db.PhoneNumberProperty() address = db.PostalAddressProperty() class Person(Contact): first_name = db.StringProperty() last_name = db.StringProperty() mobile_number = db.PhoneNumberProperty() class Company(Contact): name = db.StringProperty() fax_number = db.PhoneNumberProperty()
このモデルでは、すべての Person エンティティとすべての Company エンティティに phone_number プロパティと address プロパティがあり、Contact エンティティに対するクエリは Person または Company のいずれかを返します。Person エンティティにのみ mobile_number プロパティがあります。
サブクラスは、その他のモデル クラスと同様にインスタンス化できます:
p = Person(phone_number='1-206-555-9234',
address='123 First Ave., Seattle, WA, 98101',
first_name='Alfred',
last_name='Smith',
mobile_number='1-206-555-0117')
p.put()
c = Company(phone_number='1-503-555-9123',
address='P.O. Box 98765, Salem, OR, 97301',
name='Data Solutions, LLC',
fax_number='1-503-555-6622')
c.put()
Contact エンティティに対するクエリは、Contact、Person、Company のいずれかのインスタンスを返します。次のコードは、上記で作成された両方のエンティティの情報を出力します:
for contact in Contact.all():
print 'Phone: %s\nAddress: %s\n\n'
% (contact.phone,
contact.address))
Company エンティティへのクエリは、Company のインスタンスのみを返します:
for company in Company.all() # ...
ポリモーフィック モデルの使用方法および実装方法の詳細については、PolyModel クラスをご覧ください。
データストアは、エンティティ プロパティの一定の値の種類のセット(Unicode 文字列、整数、浮動小数点数、日付、エンティティ キー、バイト文字列(BLOB)、各種 GData 型など)をサポートします。データストアの値の種類には、それぞれに google.appengine.ext.db モジュールが提供する Property クラスがあります。
型とプロパティ クラス には、サポートされる値の種類とその Property クラスがすべて記載されています。いくつかの特殊な値の種類について以下に説明します。
データストアは、テキスト保存用に 2 種類の値の型をサポートしています。最長 500 バイトの短いテキスト文字列と、最長 1 メガバイトの長いテキスト文字列です。短い文字列はインデックス化され、クエリのフィルタ条件と並び替え順序で使用できます。長い文字列はインデックス化されず、フィルタ条件や並び替え順序には使用できません。
短い文字列の値は unicode 値と str 値のどちらかです。値が str であれば、'ascii' のエンコードが想定されます。str 値に別のエンコードを指定する場合、str とエンコード名を引数とする unicode() 型コンストラクタを使用すれば unicode 値に変換できます。短い文字列をモデリングするには、StringProperty クラスを使用します。
class MyModel(db.Model):
string = db.StringProperty()
obj = MyModel()
# Python Unicode literal syntax fully describes characters in a text string.
obj.string = u"kittens"
# unicode() converts a byte string to a Unicode value using the named codec.
obj.string = unicode("kittens", "latin-1")
# A byte string is assumed to be text encoded as ASCII (the 'ascii' codec).
obj.string = "kittens"
# Short string properties can be used in query filters.
results = db.GqlQuery("SELECT * FROM MyModel WHERE string = :1", u"kittens")
長い文字列の値は、db.Text インスタンスによって表現されます。そのコンストラクタの引数は unicode 値、または str 値と必要に応じて str で使用するエンコード名です。長い文字列をモデリングするには、TextProperty クラスを使用します。
class MyModel(db.Model):
text = db.TextProperty()
obj = MyModel()
# Text() can take a Unicode value.
obj.text = db.Text(u"lots of kittens")
# Text() can take a byte string and the name of an encoding.
obj.text = db.Text("lots of kittens", "latin-1")
# If no encoding is specified, a byte string is assumed to be ASCII text.
obj.text = db.Text("lots of kittens")
# Text properties can store large values.
obj.text = db.Text(open("a_tale_of_two_cities.txt").read(), "utf-8")
データストアでは、非テキスト バイト文字列について db.ByteString と db.Blob という類似の 2 つの型もサポートしています。これらの値は未加工のバイト文字列で、エンコードされたテキスト(UTF-8 など)としては処理されません。
str または unicode 値と同様に、db.ByteString 値はインデックス付けされ、500 文字までに制限されます。ByteString インスタンスは短いバイトの文字列を表し、そのコンストラクタに str 値を引数として渡します。バイト文字列は ByteStringProperty クラスを使用してモデリングされます。
db.Text と同様に、db.Blob 値は最大 1 メガバイトですが、インデックス付けされず、クエリ フィルタまたは並び替え順序には使用できません。db.Blob クラスはコンストラクタに str 値を引数として渡します。BLOB のモデリングには BlobProperty クラスを使用します。
class MyModel(db.Model):
blob = db.BlobProperty()
obj = MyModel()
obj.blob = db.Blob(open("image.png").read())
プロパティは、Datastore API に Python list として表現された複数の値を持つことができます。このリストには、データストアがサポートしている値の種類の値を含めることができます。単一のリスト プロパティでも複数の種類の値を持つことができます。順序は保存されるため、クエリと get() によってエンティティが返されるとき、リスト プロパティの値は保存されたときと同じ順序になります。
ListProperty クラスはリストをモデリングし、リスト内のすべての値が指定された種類となるようにします。便宜上、ライブラリは StringListProperty(ListProperty(basestring) と同等の)も提供します。
class MyModel(db.Model): numbers = db.ListProperty(long) obj = MyModel() obj.numbers = [2, 4, 6, 8, 10] obj.numbers = ["hello"] # ERROR: MyModel.numbers must be a list of longs.
リスト プロパティのクエリ フィルタは、指定された値をリストのメンバーと照合します。リストのメンバーの少なくとも 1 つがその条件に一致すれば true です。
# Get all entities where numbers contains a 6.
results = db.GqlQuery("SELECT * FROM MyModel WHERE numbers = 6")
# Get all entities where numbers contains at least one element less than 10.
results = db.GqlQuery("SELECT * FROM MyModel WHERE numbers < 10")
クエリ フィルタの対象はリスト メンバーのみです。1 つのクエリ フィルタ内で 2 つのリストの類似性をチェックする方法はありません。
内部的には、データストアはリスト プロパティ値をそのプロパティを表す複数の値で表現します。リスト プロパティ値が空のリストであれば、そのプロパティはデータストアで表現されません。Datastore API がこの状況を処理する方法は、静的プロパティ(ListProperty を持つ)の場合と動的プロパティの場合で異なります。
None の値を持つことはできません。list 値を持つ動的プロパティには、空のリスト値を割り当てることはできません。ただし、この動的プロパティは None の値を持つことができるほか、del を使用して削除することもできます。ListProperty モデルは、リストに追加された値の種類が正しいかどうかテストし、正しくなければ BadValueError をスローします。このテストは、以前に保存されたエンティティを取得してモデルにロードするときに実行されます(エラーになる可能性があります)。str 値は保存前に unicode 値に(ASCII テキストとして)変換されるので、ListProperty(str) は ListProperty(basestring) (str と unicode のどちらの値も受け入れる Python データ型)として処理されます。StringListProperty() もこの目的に使用できます。
テキスト以外のバイト文字列を保存するには、db.Blob 値を使用します。BLOB 文字列のバイトは、格納時や取得時に保存されます。BLOB のリストであるプロパティは、ListProperty(db.Blob) として宣言できます。
リスト プロパティは、並び替え順序を使用して、一般的でない方法でやり取りします。詳細は、クエリとインデックス: 複数の値での並び替え順序とプロパティ をご覧ください。
プロパティ値には、別のエンティティのキーを格納できます。その値は Key インスタンスです。
ReferenceProperty クラスはキー値をモデリングし、すべての値が指定された種類のエンティティを参照するようにします。便宜上、ライブラリは、プロパティを持つエンティティと同じ種類を参照する ReferenceProperty と同等の SelfReferenceProperty も提供します。
モデル インスタンスを ReferenceProperty プロパティに割り当てると、そのキーが自動的に値として使用されます。
class FirstModel(db.Model): prop = db.IntegerProperty() class SecondModel(db.Model): reference = db.ReferenceProperty(FirstModel) obj1 = FirstModel() obj1.prop = 42 obj1.put() obj2 = SecondModel() # A reference value is the key of another entity. obj2.reference = obj1.key() # Assigning a model instance to a property uses the entity's key as the value. obj2.reference = obj1 obj2.put()
ReferenceProperty プロパティは、参照されているエンティティのモデル インスタンスと同じように使用できます。参照されているエンティティがメモリ内にない場合、そのプロパティをインスタンスとして使用すると、そのエンティティが自動的にデータストアからフェッチされます。
obj2.reference.prop = 999
obj2.reference.put()
results = db.GqlQuery("SELECT * FROM SecondModel")
another_obj = results.fetch(1)[0]
v = another_obj.reference.prop
エンティティのキーが参照プロパティの値である場合、そのエンティティを削除しても、その参照プロパティは変わりません。参照プロパティ値は、有効でなくなったキーにすることもできます。アプリケーションでは、参照が有効でない可能性を予測すると、if ステートメントを使用して、オブジェクトの存在をテストすることができます。
obj1 = obj2.reference if not obj1: # Referenced entity was deleted.
ReferenceProperty には他にも、後方参照という便利な機能があります。モデルが他のモデルに対する ReferenceProperty を持つ場合、参照されている各エンティティが取得するプロパティの値は、それを参照する最初のモデルのエンティティをすべて返す Query です。
# To fetch and iterate over every SecondModel entity that refers to the # FirstModel instance obj1: for obj in obj1.secondmodel_set: # ...
後方参照プロパティの名前は modelname_set (小文字のモデル クラス名の後に「_set」を付けたもの)にデフォルト設定され、ReferenceProperty コンストラクタに渡す collection_name 引数を使用して調整することができます。
同じモデル クラスを参照する ReferenceProperty 値を複数使用した場合、デフォルトで後方参照プロパティを生成するとエラーが発生します。
class FirstModel(db.Model): prop = db.IntegerProperty() # This class raises a DuplicatePropertyError with the message # "Class Firstmodel already has property secondmodel_set" class SecondModel(db.Model): reference_one = db.ReferenceProperty(FirstModel) reference_two = db.ReferenceProperty(FirstModel)
このエラーを回避するには、collection_name 引数を明示的に設定する必要があります。
class FirstModel(db.Model):
prop = db.IntegerProperty()
# This class runs fine
class SecondModel(db.Model):
reference_one = db.ReferenceProperty(FirstModel,
collection_name="secondmodel_reference_one_set")
reference_two = db.ReferenceProperty(FirstModel,
collection_name="secondmodel_reference_two_set")
モデル インスタンスの自動参照および逆参照、型チェック、後方参照が使用できるのは、ReferenceProperty モデル プロパティ クラスの場合のみです。Expando 動的プロパティの値や ListProperty 値として格納されたキーには、このような機能はありません。
データストアは、最初と最後に 2 つの下線文字(__*__)を使用したすべてのプロパティ名を保存します。アプリケーションは、そのような名前のプロパティを作成することはできません。
Python API では、下線(_)で始まる名前のモデル インスタンスの属性は無視され、データストア エンティティに保存されません。これによって、エンティティと一緒に保存されたデータに影響を及ぼすことなく、モデル インスタンスの値を格納して、一時的に内部利用できるようになります。
Python API はデフォルトでモデル インスタンスの属性をプロパティ名として使用するので、インスタンス メソッドですでに使用している属性をプロパティの属性名として直接使用することはできません。同様に、モデル コンストラクタのキーワード引数で使用されている名前も、プロパティの属性名として使用することはできません。詳細については、予約済みプロパティ名のリストをご覧ください。
データストアそのものにはこれらの名前を使用できます。アプリケーションでは、データストア エンティティに Python API の予約語と同じ名前のプロパティを持たせる必要がある場合、固定プロパティを使用して、その Property クラスのコンストラクタに name 引数を渡すことができます。Property クラスのコンストラクタをご覧ください。
class MyModel(db.Model): obj_key = db.StringProperty(name="key")