お気に入り | 日本語 | ログイン

データの作成、取得、削除

Datastore API はエンティティをモデル クラスのインスタンスとして表現します。モデル インスタンスのメソッドは、エンティティを作成、更新、削除します。エンティティは、クエリまたはキーを使用して、データストアからモデル インスタンスとしてフェッチできます。

エンティティの作成と更新

Model(および Expando)クラスのインスタンスはデータストア エンティティを表します。アプリケーションは、対応するモデル クラスのコンストラクタを呼び出して、指定された種類の新しいエンティティを作成します。

pet = Pet(name="Fluffy",
          type="cat",
          owner=users.get_current_user())

インスタンスに対して put() メソッドが呼び出されるか、インスタンスが db.put() 関数に渡され、インスタンスが初めて「入力」されるまで、データストアに新しいエンティティは作成されません。

pet.put()

db.put(pet)

インスタンスがすでに格納されている場合は、put() メソッドが既存のエンティティを更新します。

クエリは結果をモデル インスタンスとして返します。これらのインスタンスは修正され、データストアに戻されます。

if users.get_current_user():
  user_pets = db.GqlQuery("SELECT * FROM Pet WHERE owner = :1",
                          users.get_current_user())
  for pet in user_pets:
    pet.spayed_or_neutered = True

  db.put(user_pets)

クエリを使用したエンティティの取得

データストアは指定された種類のエンティティ全体にクエリを実行することができます。クエリは、エンティティ プロパティ値が満たさなければならない条件を使用して結果をフィルタし、プロパティ値でソートされた結果を返します。クエリは指定された祖先を使用して、エンティティの範囲を制限することも可能です。キーとエンティティ グループをご覧ください。

クエリができないことも含めた、クエリの動作に関する全体的な説明は、クエリとインデックスをご覧ください。

Datastore API は、エンティティ プロパティでクエリを実行するために 2 つのインターフェースを提供します。Query は、クエリ オブジェクトにメソッドを使用してクエリを作成するインターフェースです。GqlQuery は、SQL に似たクエリ言語である GQL を使用するインターフェースです。

Query インターフェース

all() メソッドが Model(または Expando)クラスに使用されると、対応する種類のすべてのエンティティに対するクエリを表す Query オブジェクトを返します。アプリケーションはオブジェクトに対して filter()order()、およびancestor() メソッドを呼び出してクエリを作成します。

class Story(db.Model):
  title = db.StringProperty()
  date = db.DateTimeProperty()

query = Story.all()

query.filter('title =', 'Foo')
query.order('-date')
query.ancestor(key)

# These methods can be chained together on one line.
query.filter('title =', 'Foo').order('-date').ancestor(key)

GqlQuery インターフェース

GqlQuery クラスのコンストラクタは GQL クエリ文字列と任意のパラメータ バインディングを使用します。クエリ文字列は種類、フィルタ、ソート順序、祖先の条件を指定します。クエリ文字列は結果の制限とオフセットも含むことができます。

# Parameters can be bound with positional arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :1 "
                    "AND ANCESTOR IS :2 "
                    "ORDER BY date DESC",
                    'Foo', key)

# Or, parameters can be bound with keyword arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :title "
                    "AND ANCESTOR IS :parent "
                    "ORDER BY date DESC",
                    title='Foo', parent=key)

# String, number and Boolean values can be literal values in the string.
query = db.GqlQuery("SELECT * FROM Story WHERE title = 'Foo' "
                    "AND ANCESTOR IS :parent "
                    "ORDER BY date DESC",
                    parent=key)

Model クラスの gql() クラス メソッドも文字列から GqlQuery オブジェクトを作成します。文字列は、SELECT * FROM Model 部分が省略された GQL クエリ文字列です。この部分は暗黙に示されているからです。

query = Story.gql("WHERE title = :title "
                  "AND ANCESTOR IS :parent "
                  "ORDER BY date DESC",
                  title='Foo', parent=key)

パラメータ バインディングは bind() メソッドを使用して、新しい値に再バインドできます。アプリケーションは、パラメータを再バインドし、クエリを再実行することで、GqlQuery オブジェクトを再使用できます。

クエリの実行と結果へのアクセス

Query および GqlQuery オブジェクトは、アプリケーションが結果にアクセスしようとするまでは実行されません。アプリケーションが結果にアクセスするとクエリが実行され、結果はクエリのモデル クラスのインスタンスとしてメモリにロードされます。いずれのクエリ クラスにも 2 通りのクエリの実行と結果へのアクセス方法があります: fetch() メソッドとイテレータ インターフェースです。

fetch() メソッドはフェッチ用に最大数の結果(制限)とスキップ用に任意の数の結果(オフセット)を使用します。メソッドはクエリを実行し、結果を制限までフェッチするか、結果がなくなるまでフェッチします。結果がメモリにロードされると、オフセットが指定されている場合はオフセットまでスキップし、モデル インスタンスのリストとしてリクエストされた結果を返します。fetch() が呼び出されるたびにクエリが完全に実行されます。

注: オフセットはデータストアからフェッチされる結果の数には影響しません。すべての結果は制限までフェッチされ、メモリに格納されます。オフセットは fetch() メソッドで返されるものに限って影響します。

results = query.fetch(10)
for result in results:
  print "Title: " + result.title

fetch() メソッドに指定された制限とオフセットは、GQL クエリ文字列で指定された制限とオフセットをオーバーライドします。

クエリ オブジェクトがイテレータとして使用された場合、クエリは制限にもオフセットにも関係なく実行され、結果はメモリにロードされます。返される値は結果に対するイテレータとなります。イテレータはモデル クラスのインスタンスを生成します。

for result in query:
  print "Title: " + result.title

注: データストアは、結果をフェッチするために使用する制限やオフセットには関係なく、1 つのクエリに対して最大 1,000 件の結果を返します。1,000 件の結果には、オフセットの使用によってスキップされたものもすべて含まれます。したがって、1,000 件を超える結果を持つクエリが 100 のオフセットを使用する場合、900 件の結果が返されます。

キーを使用したエンティティの取得

エンティティは、データストアに格納された後、一意のキーを持ちます。キー値は API では Key クラスのインスタンスとして表されます。モデル インスタンスの put() メソッドと db.put() 関数は、格納されたエンティティの Key を返します。初めてモデル インスタンスが格納された後、モデル インスタンスの key() メソッドはインスタンス用の Key を返します。

entity.put()
key = entity.key()

# ...

entity = db.get(key)

Key 値は一般的に、別のエンティティのプロパティ値として格納するために使用されます。ReferenceProperty モデル プロパティ クラスは、キーとしてのモデル インスタンスの自動参照と逆参照を提供します。 モデル インスタンスは ReferenceProperty に直接割り当てることができ、そのキーは値として使用されます。

class PetOwner(db.Model):
  name = db.StringProperty()

class Pet(db.Model):
  name = db.StringProperty()
  owner = db.ReferenceProperty(PetOwner)

owner = PetOwner(name="Albert")
pet = Pet(name="Fluffy", owner=owner)

# This is equivalent:
pet = Pet(name="Fluffy", owner=owner.key())

同様に、プロパティ経由でアクセスされた ReferenceProperty 値はそのインスタンスと同じように動作します。データ エンティティは自動的にフェッチされ、それが使用されるまでフェッチされません。

pets = db.GqlQuery("SELECT * FROM Pet WHERE name = :1", "Fluffy")
pet = pets.get()

owner_name = pet.owner.name

Expando 動的プロパティや ListProperty 要素のように、ReferenceProperty モデルなしに格納された Key 値は、自動的に逆参照しません。

db.get() 関数は Key(または Key のリスト)用に、データストアからエンティティをフェッチします。

キーは、アプリケーション外部での受け渡しのために文字列としてエンコードすることができます。文字エンコードされたキーを Key オブジェクトに変換し直すためには、アプリケーションは文字列を Key コンストラクタに渡します。

obj = MyModel(name="Foo")
self.response.write('<a href="/view?key=%s">%s</a>' % (str(obj.key()), 
                                                      obj.name()))

# ...

key_name = self.request.get('key')
obj = db.get(db.Key(key_name))

注: Key の文字エンコーディングは不明瞭ですが、暗号化されていません。推測できないキーが必要なアプリケーションの場合は、文字エンコードされた Key をさらに暗号化した後、ユーザーに転送するようにしてください。

エンティティの削除

アプリケーションは、モデル インスタンスまたは Key を使用してデータストアからエンティティを削除することができます。モデル インスタンスの delete() メソッドは、対応するエンティティをデータストアから削除します。delete() 関数は、Key または Key のリストを使用してデータストアからエンティティを削除します。

q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
for result in results:
  result.delete()

# or...

q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
db.delete(results)

エンティティを削除しても、そのエンティティを参照していたデータストア内の Key 値は変更されません。アプリケーションが削除されたエンティティの Key 値を逆参照しようとした場合、アプリケーションは db.get() を使用して逆参照し、プロパティにアクセスする前に戻り値をテストすることができます。

別のエンティティの祖先であるエンティティを削除しても、他のエンティティに影響はありません。子孫エンティティの Key を構築する上で祖先に依存しているアプリケーションでなければ、アプリケーションは子孫にもアクセスできます。