NDB Model クラス

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() からの戻り値は Key です。これは後で同じエンティティを取得するときに使用できます。

p2 = k.get()
p2 == p  # Returns True

エンティティを更新するには、属性を変更してもう一度書き込みます(この操作を行っても、キーは変更されません)。

p2.name = 'Arthur Philip Dent'
p2.put()

キーを使用してエンティティを削除することもできます。

k.delete()

クラス本体のプロパティ定義は、Datastore に保存されたフィールドの名前とタイプ、インデックスを付けるかどうか、デフォルト値などをシステムに示します。プロパティの型には、さまざまなものがあります。

kind は通常、クラス名と同じです(ただし、モジュール名や親スコープは除きます)。kind をオーバーライドする(スキーマの変更に役立ちます)には、次のように _get_kind() という名前のクラスメソッドを定義します。

  class MyModel(ndb.Model):
    @classmethod
    def _get_kind(cls):
      return 'AnotherKind'

アプリケーションでは、別のモジュールに存在する場合でも、同じ種類のモデルクラスを 2 つ定義することは避ける必要があります。アプリケーションの種類は、グローバルな名前空間とみなされます。

Model サブクラスでは、ほとんどのオペレーション(get、put、delete、allocate_ids)に対してプリコールとポストコールのフックを定義できます。

コンストラクタ

通常、アプリケーションは、Model() を呼び出さず、Model から継承したクラスのコンストラクタを呼び出します。これにより、このモデルの新しいインスタンスが作成されます。これはエンティティとも呼ばれます。

新しく作成されたエンティティは、Datastore に自動的には書き込まれません。そうするには、put() を明示的に呼び出して、Datastore に書き込む必要があります。

引数

Model サブクラスでは、次のキーワード引数がサポートされます。

key
このモデルのキー インスタンス。key パラメータを使用する場合、idparent は、None(デフォルト)にする必要があります。
id
このモデルのキー ID。id を使用する場合、key は、None(デフォルト)にする必要があります。
parent
親モデルの key インスタンス。最上位モデルの場合は Noneparent を使用する場合、keyNone にする必要があります。
namespace
このエンティティで使用する名前空間。現在の名前空間を使用する場合は、None(デフォルト)。namespace を使用する場合、keyNone にする必要があります。

また、アプリケーションでは、キーワード引数を使用して、モデルのプロパティにマッピングできます。たとえば、次のとおりです:

class Person(ndb.Model):
  name = StringProperty()
  age = IntegerProperty()

p = Person(name='Arthur Dent', age=42)

「key」、「id」、「parent」、「namespace」という名前のプロパティは、簡単には定義できません。たとえば、コンストラクタや populate() の呼び出しで key="foo" を渡すと、エンティティのキーは設定されますが、「key」 という名前のプロパティ属性は設定されません。

注: Model サブクラスでコンストラクタをオーバーライドすると、コンストラクタが暗黙的に呼び出される場合があるため、このような呼び出しをサポートする必要があります。Datastore からエンティティを読み取るときには、引数なしでコンストラクタを呼び出して、空のエンティティが作成されます。その後、キーとプロパティの値が 1 つずつ設定されます。get_or_insert()get_or_insert_async() で新しいインスタンスを作成するときは、コンストラクタに **constructor_args が渡されてキーが設定されます。

クラス メソッド

allocate_ids(size=None, max=None, parent=None, **ctx_options)

このモデルクラスに対するキー ID の範囲を割り当てます。

引数

size
割り当てる ID の数。size または max を指定できます。両方は指定できません。
max
割り当てる ID の最大数。size または max を指定できます。両方は指定できません。
parent
ID を割り当てる親キー。
**ctx_options
コンテキスト オプション

割り当てた範囲に対する(start, end)のタプルを返します(両端を含みます)。

アプリケーションが、トランザクションで allocate_ids() を呼び出すことはできません。

allocate_ids_async(size=None, max=None, parent=None, **ctx_options)

allocate_ids の非同期バージョン。

結果が割り当てた範囲に対する(start, end)のタプル(両端を含む)となる Future オブジェクトを返します。

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
親エンティティ キー(存在する場合)。
アプリ
アプリの 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 の非同期バージョンです。

結果が指定したキー名と親を持つ Model クラスの既存のインスタンスか、新しく作成されたインスタンスとなる Future オブジェクトを返します。

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)

エンティティのデータをデータストアに書き込みます。エンティティのキーを返します。

引数

**ctx_options
コンテキスト オプション
put_async(**ctx_options)

エンティティのデータをデータストアに非同期的に書き込みます。Future オブジェクトを返します。Future オブジェクトの結果は、エンティティの Key になります。

引数

**ctx_options
コンテキスト オプション
to_dict(include=all, exclude=None)

モデルのプロパティ値を含む dict を返します。StructuredPropertyLocalStructuredProperty のプロパティ値は、再帰的に辞書に変換されます。

引数

include
含めるプロパティのオプション リスト。デフォルトでは、すべてが対象です。
exclude
除外するプロパティのオプション リスト。includeexclude が重なっている場合は、exclude が優先されます。

注: プロパティ値が、可変オブジェクト(反復プロパティを表すリスト、JsonProperty に格納されている辞書やリストなど)の場合、値が明示的に変換されない限り(StructuredProperty の場合など)、エンティティに保存されている辞書に同じオブジェクトが返されます。この場合、辞書を変更すると、エンティティが変更されます(その逆も可)。

インスタンス データ

key
Model キーを保存する特別なプロパティ。

フックメソッド

アプリケーションの Model のサブクラスでは、オペレーション前後の「フック」メソッドとして 1 つ以上のメソッドを定義できます。たとえば、各「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() と同じです。これは、常に _ で始まるメソッド名を使用すると、メソッド名とプロパティ名が競合する可能性があることを意味します。しかし、コンストラクタに keyparentid という名前のプロパティを指定することはできません。

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.

任意のモデルを操作するサードパーティ ライブラリを作成する場合は、_ で始まるメソッド名の使用をおすすめします。