データベース API リファレンス

revision-up-to:8001 (1.0pre SVN)

データモデル を作成したら、次はデータベースからデータを取り出す必要があ ります。このドキュメントでは、モデルから利用できるデータベース抽象化 API と、 オブジェクトを生成、取得、更新する方法について説明します。

このリファレンスでは、以下のような Poll アプリケーションを参考に話を進めま す:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __unicode__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateTimeField()
    authors = models.ManyToManyField(Author)

    def __unicode__(self):
        return self.headline

オブジェクトの生成

Django では、データベーステーブル上のデータを Python オブジェクトで表現する ために、モデルクラスがデータベーステーブルを表現し、クラスのインスタンスが テーブル上のレコードを表現するという直感的なシステムを使っています。

オブジェクトを生成するには、キーワード引数を使ってモデルクラスのインスタン スを生成し、 save() メソッドを呼び出してデータベースに保存します。

モデルクラスは Python パス上のどこからでも import でき、期待通りに動作しま す (わざわざこのような説明をするのは、以前のバージョンの Django ではモデル の import 方法がかなり風変わりだったからです)。

モデルが mysite/blog/models.py というファイルで定義されているとすると、 オブジェクトの作成は以下の例のようになります:

from mysite.blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()

この操作によって、背後では INSERT SQL 文が実行されます。 Django はユー ザが明示的に save() を呼び出すまでデータベースを操作しません。

ワンステップでオブジェクトを生成して保存するには create メソッドを使 います。

主キーの自動インクリメント

モデルに AutoField 、すなわち自動インクリメントされる主キーがある場合に は、オブジェクトに対して最初に save() を呼び出したときに自動インクリメ ント値が計算され、保存されます。

例えば:

b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
b2.id     # b には ID がないので None を返します。
b2.save()
b2.id     # 新たに保存されたオブジェクトの ID を返します。

ID の値は Django ではなくデータベースによって計算されるので、 save() を 呼び出すまでは ID の値は分かりません。

(利便性のため、明示的に primary_key=True を指定したフィールドを作成しな いかぎり、デフォルトでは各モデルに id という名前の AutoField が追加されます。詳しくは AutoField のドキュメント を参照してください。)

自動主キーの値を明示的に指定する

モデルが AutoField を持っていて、新たなオブジェクトの ID を保存時に明示 的に指定したい場合、 ID を自動的に決定させずに保存前に明示的に指定してくだ さい。

例えば:

b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
b3.id     # Returns 3.
b3.save()
b3.id     # Returns 3.

自動主キーの値を手動で割り当てる場合、決して既に存在する主キーの値を割り当 てないようにしてください! 明示的な主キー値を持った新たなオブジェクトを作成 し、その主キーがすでにデータベース上に存在する場合、 Django は保存操作を新 たなオブジェクトの作成ではなく、既存のオブジェクトの変更とみなします。

上の 'Cheddar Talk' ブログを例にとると、以下の例はデータベース上の既存 のレコードをオーバライドしてしまいます:

b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save()  # Overrides the previous blog with ID=3!

この理由については後述の UPDATE と INSERT の区別 を参照してください。

主キーの衝突がないとはっきり判っている場合なら、自動主キーの値の明示的な指 定は大量のオブジェクトを保存する際にきわめて便利です。

オブジェクトの保存時に何が起きるのか

Django は以下の段階を踏んでオブジェクトを保存します:

  1. ``pre_save`` シグナルの発行 シグナルの発行によって、何らかのオブ ジェクトを保存しようとしていることを通知します。リスナ (listener) を 用意して登録しておけ、 pre_save シグナルが発行された時に実行でき ます (シグナルのドキュメントはまだありません)。

  2. データの前処理 オブジェクトの各フィールドについて、保存時に自動 的に実行する必要があるデータ修飾処理がないか調べ、あれば実行します。

    ほとんどのフィールドは前処理を 伴いません 。フィールドのデータは そのまま保存されます。前処理が行われるのは、特殊な挙動を示すフィー ルドだけです。例えば、 auto_now=True に設定された DateField の場合、前処理の段階で、フィールドの内容が現在の日付になるようデータ を置き換えます (現時点では、「特殊な」挙動を示すフィールドのリストを 全て列挙したドキュメントはありません)。

  3. データベース保存用のデータ準備処理 各フィールドについて、フィー ルドの現在の値を元にデータベースに保存できる型のデータを生成します。

    ほとんどのフィールドはデータ準備処理を 伴いません 。整数や文字列は Python オブジェクトとして「いつでもデータベースへの書き込みに使える」 形式になっています。ただ、より複雑なデータ型の場合、なにがしかの修飾 が必要なことがあります。

    例えば、 DateField は、データの保存に Python の datetime 型 を使います。データベースは datetime オブジェクトを保存しないので、 データベースに保存するには、フィールドの値を ISO 準拠の日付文字列に 変換せねばなりません。

  4. データベースへの保存 前処理と準備処理を経たデータが SQL 文に組み 込まれ、データベースに挿入されます。

  5. ``post_save`` シグナルの発行 pre_save シグナルと同じく、オブ ジェクトが成功理に保存されたことを通知するために post_save シグ ナルが発行されます (シグナルのドキュメントはまだありません)。

オブジェクトへの変更を保存する

すでにデータベース上にあるオブジェクトへの変更を保存するには save() を 使います。

Blog インスタンス b5 がすでにデータベース上にあるとすると、以下の例 は b5 の名前を変更して、データベース上のレコードを更新します:

b5.name = 'New name'
b5.save()

この例では、背後で UPDATE SQL 文が実行されています。 Django は明示的に save() を呼び出すまでデータベースを操作しません。

save() メソッドには戻り値がありません。

ForeignKey や ManyToManyField の保存

ForeignKey フィールドの更新は、通常のフィールドへの変更と同じです。すな わち、適切な型のオブジェクトを代入して保存すると、フィールドの値を更新でき ます:

cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()

ManyToManyField の更新は少し違います。リレーションにレコードを一つ追加 したい場合は add() メソッドを使います:

joe = Author.objects.create(name="Joe")
entry.authors.add(joe)

間違った型のオブジェクトを外部キーに代入したり add() したりすると Django はエラーを出します。

UPDATE と INSERT の区別

Django データベースオブジェクトがオブジェクトの作成と変更に同じ save() メソッドを使っていることにお気づきかもしれませんね。 Django は INSERTUPDATE SQL 文のどちらを使うべきかの判断を抽象化しています。具体的 に言うと、 save() を呼び出したときに、Django は以下のアルゴリズムに従い ます:

  • オブジェクトの主キー属性の評価値が False でない場合 (None や 空文字列の場合などでない場合) 、 Django は SELECT クエリを使って、 該当する主キーを持つレコードが存在するかどうか調べます。
  • 該当する主キーを持つレコードがデータベース上に存在する場合には UPDATE クエリを使います。
  • オブジェクトの主キー属性が設定 されていない 場合や、主キーが設定さ れているが該当するレコードは存在しない場合、 INSERT を使います。

新たなオブジェクトを保存する際、まだ使われていない値を主キーに指定できる保 証がないかぎり、主キーの値を明示的に指定しないよう注意してください。詳しく は上記の 自動主キーの値を明示的に指定する を参照してください。

オブジェクトの取得

オブジェクトをデータベースから取得するには、モデルクラスのマネジャ (Manager) を介してクエリセット (QuerySet) を構築します。

クエリセットはデータベース上にあるオブジェクトの集まりを表現しています。 クエリセットには、集合を指定パラメタに従って絞り込むための条件である フィルタ (filter) がゼロ個から複数個あります。 SQL 用語でいえば、 クエリセットは SELECT 文であり、フィルタは WHERELIMIT のような限定節にあたります。

クエリセットはモデルのマネジャから取得します。モデルには最低一つの マネジャがあり、デフォルトでは objects という名前がついています。 マネジャにはモデルクラスから直接アクセスしてください:

Blog.objects  # <django.db.models.manager.Manager object at ...>
b = Blog(name='Foo', tagline='Bar')
b.objects     # AttributeError: "Manager isn't accessible via Blog instances."

(「テーブルレベル」の操作と「レコードレベル」の操作を分離させるため、マネジャ はモデルのインスタンスではなくモデルクラスだけからアクセスできるようになっ ています。)

モデル内でのクエリセットの主なソースはマネジャです。マネジャは、データベー スオブジェクト上の全てのオブジェクトを表す「ルートの」クエリセットであるか のように振舞います。例えば、初期クエリセットである Blog.objects には、 データベース上の全ての Blog オブジェクトが入っています。

全てのオブジェクトの取得

テーブルからオブジェクトを取得する最も単純な方法では、全てのオブジェクトを 取得します。マネジャの all() メソッドを使って下さい。

例えば:

all_entries = Entry.objects.all()

all() メソッドはデータベース上の全てのオブジェクトを表現するクエリセッ トを返します。

(Entry.objects がクエリセットを返すというのなら、なぜ単に Entry.objects と書かないのでしょうか?それは、ルートのクエリセットであ る Entry.objects が特別扱いされていて、値評価できないようになっているか らです。 all() メソッドは、値評価 できる クエリセットを返します。

オブジェクトのフィルタ操作

マネジャによって提供されるクエリセットを使えば、データベーステーブル上の全 てのオブジェクトを表せます。とはいえ、通常は全オブジェクトの集合からサブセッ トだけを取り出したいことでしょう。

サブセットを作成するには、フィルタ条件を追加して、初期クエリセットをリファ インする必要があります。クエリセットの洗練には、主に二つの方法があります:

filter(**kwargs)
指定した照合パラメタに一致するオブジェクトの集合を表現する、新たなクエ リセットを返します。
exclude(**kwargs)
指定した照合パラメタに一致 しない オブジェクトの集合を表現する、新た なクエリセットを返します。

照合パラメタ (上の関数定義における **kwargs) は、後述の フィールドの照合 で解説するフォーマットにせねばなりません。

例えば、 2006 年のブログエントリを表すクエリセットを取得するには、以下のよ うに filter() を使います:

Entry.objects.filter(pub_date__year=2006)

(Entry.objects.all().filter(...) のように、 all() を使わなくてもよ いことに注意して下さい。 all() を使っても問題なく動作しますが、 all() が必要となるのはルートクエリセットから全てのオブジェクトを取り出 したい場合だけです。)

フィルタの連鎖

クエリセットをリファインした結果は、それ自体クエリセットになります。従って、 リファイン操作は連鎖させられます。例えば:

Entry.objects.filter(
    headline__startswith='What').exclude(
        pub_date__gte=datetime.now()).filter(
            pub_date__gte=datetime(2005, 1, 1))

上の例は、データベースの全てのエントリを表す初期クエリセットに対し、 filter() をかけた後に exclude() を実行し、さらにもう一つ filter() をかけています。最終的に得られるのは、 "What" で始まる ヘッドラインのうち、 January 1, 2005 から今日までの間に公開されたエントリに なります。

フィルタしたクエリセットは一意になる

クエリセットのリファインを行うと、その都度新たなクエリセットを得ます。新た なクエリセットは以前のクエリセットになんら縛られていません。リファイン操作 のたびに、別個の独立したクエリセットが作成され、個別に保存したり、再利用し たりできます。

例えば:

q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.now())
q3 = q1.filter(pub_date__gte=datetime.now())

これら 3 つのクエリセットは別個のものです。最初はヘッドラインが "What" で始 まる全てのエントリの入ったベースのクエリセットです。二つ目のクエリセットは、 最初のクエリセットのサブセットであり、 pub_date の値が現在時刻よりも大 きいものを排除します。三つ目のクエリセットも最初のクエリセットのサブセット で、 pub_date の値が現在時刻よりも大きいものだけを選択するようになって います。こうしたリファイン操作は、初期クエリセット (q1) に影響を及ぼし ません。

クエリセットは遅延評価される

クエリセットの評価は遅延型 (lazy) です。すなわち、クエリセットの作成自体は データベース操作を引き起こしません。クエリセットは 評価される までデータ ベースへのクエリを実行しないので、延々フィルタを重ねられます。

クエリセットはいつ評価されるのか

以下の方法を使うと、クエリセットを評価できます:

  • イテレーション。 クエリセットはイテレーション可能オブジェクトであ り、オブジェクトに対して最初にイテレーション操作を行ったときにデータ ベースクエリを実行します。例えば、以下の例はデータベース中の全てのエ ントリのヘッドラインを出力します:

    for e in Entry.objects.all():
        print e.headline
    
  • スライス。 クエリセットに制約を課す の節で説明しているように、 Python の配列スライス表記を使うとクエリセットをスライスできます。通常、 クエリセットに対するスライスは (未評価の) 別のクエリセットを返します が、スライス表記に「ステップ (step)」パラメタを使った場合には、データ ベースクエリを実行します。

  • repr(). クエリセットに対して repr() を呼び出すと、クエリセッ トは値評価されます。これは Python 対話インタプリタでの利便性のための 仕様で、 API を対話的に使うときに結果を即座に見られるようにしています。

  • len(). クエリセットに対して len() を呼び出すと、クエリセッ トは値評価されます。予想に違わず、 len() はクエリ結果リストの長さ を返します。

    注意: クエリセット中のレコードの数を知りたいだけなら、 len()使わないでください 。レコード数の計算はデータベース上で SQL 文の SELECT COUNT(*) 使って行う方が遥かに効率的であり、まさにその理由 から Django では count() メソッドを提供しています。後述の count() を参照してください。

  • list(). クエリセットに対して list() を呼び出すと、値評価を強 制できます。例えば:

    entry_list = list(Entry.objects.all())
    

    とはいえ、この方法を使うと、Django が全ての要素のリストをメモリ上にロー ドするため、巨大なメモリオーバヘッドを引き起こす可能性があるので十分 注意してください。これに対し、クエリセットに対するイテレーション操作 では、必要な分だけデータをロードしてオブジェクトをインスタンス化する という利点があります。

クエリセットの pickle 化

クエリセットを pickle 化すると、クエリセットによって得られる内容は pickle 化に先立って全てのメモリ上にロードされます。このため、 pickle はしばしばキャッ シュに先駆けて使われたり、すでにクエリ結果が存在する場合にクエリセットをリ ロードする目的で使われます。逆に、クエリセットを逆 pickle 化すると、現在の データベース上の値ではなく、 pickle 化した当時の結果を返します。

単にクエリセットを再構築する上で必要な情報だけを pickle 化したいのなら、ク エリセットの query 属性だけを pickle 化してください。レコードの pickle 化を伴わずにクエリセットを再構築したければ、以下のようにしてください:

>>> import pickle
>>> query = pickle.loads(s)     # pickle 化文字列を 's' とします。
>>> qs = MyModel.objects.all()
>>> qs.query = query            # もとの 'query' を代入して再構築します。

クエリセットに制約を課す

クエリセットの返す結果を特定の個数に制限したい場合には、配列スライス表記を 使います。これは SQL の LIMIT 節や OFFSET 節と等価になります。

以下の例は、最初の 5 オブジェクトだけを返します (LIMIT 5 に相当します):

Entry.objects.all()[:5]

N 個目以降末尾までのスライスも可能です。例えば、 6 番目以降の要素を返さ せたければ、以下のようにします:

Entry.objects.all()[5:]

この表現がどのような SQL になるかは、使っているバックエンドによって異なりま すが、とりあえず全てのバックエンドでサポートされています。

以下の例は、 6 番目から 10 番目までのオブジェクトを返します (OFFSET 5 LIMIT 5 に相当します):

Entry.objects.all()[5:10]

一般に、クエリセットのスライスはクエリセットを返し、クエリの評価は行いませ ん。例外はスライス表記に「ステップ (step)」パラメタを使ったときです。以下の 例では、クエリを実際に実行し、最初の 10 オブジェクト中から 1 つおきにオブジェ クトを取り出したリストを返します:

Entry.objects.all()[:10:2]

リストではなく 単一の オブジェクトを取得したい場合 (SELECT foo FROM bar LIMIT 1 のような場合) には、スライスではなく単純な インデクス指定を行います。以下の例はデータベースのエントリをヘッドラインに ついてアルファベット順に整列した後、最初の Entry を取得して返します:

Entry.objects.order_by('headline')[0]

これはだいたい以下と同じになります:

Entry.objects.order_by('headline')[0:1].get()

ただし、指定条件にマッチするオブジェクトがない場合、前者は IndexError, 後者は DoesNotExist を送出します。

クエリセットを組み合わせる

同じモデルの二つのクエリセットは &| で組み合わせられます。 & で組み合わせれば二つのクエリセットの両方に存在する要素を、 | で組 み合わせれば二つのクエリセットのどちらかに存在する要素を表します。例えば:

Entry.objects.filter(pubdate__gte=date1) & \
        Entry.objects.filter(headline__startswith="What")

のようにすると、二つのクエリを組み合わせて一つの SQL クエリを生成できます。 もちろん、上の例に限って言えば、クエリセットを複数回フィルタすれば同じ結果 を得られます。しかし、クエリセットを組み合わられると便利な場合があるのです。

とはいえ、 extra() を使ってクエリセットを操作している時には注意してくだ さい。 extra() に指定した内容は、組み合わせて生成した SQL クエリの中に も組み込まれるため、その結果が意味をなさない場合があるからです。カスタムの SQL を extra() に入れると、 Django はその SQL を書き直そうとしません。 ですから、テストを注意深く実施してください。また、 | でクエリセットを組 み合わせる場合、 extra(select=...)extra(where=...)両方の クエリセットには同時に使えないので注意してください。 | を使う場合、 extra(select=...) および extra(where=...) は片方のクエリセットだけ に適用できます (正しく使われていない場合、 Django は ValueError を送出 します。

新たなクエリセットを返すクエリセットメソッド

Django では、クエリセットの返す結果の形式や、 SQL クエリの実行方法を変更す るためのリファインメソッドを幅広く提供しています。

filter(**kwargs)

指定の照合パラメタに一致するオブジェクトの入った新たなクエリセットを返しま す。

照合パラメタ (**kwargs) は後述の フィールドの照合 で説明するフォーマッ トにします。複数のパラメタを指定すると、背後の SQL 文では AND で結合さ れます。

exclude(**kwargs)

指定の照合パラメタに一致 しない オブジェクトの入った新たなクエリセットを 返します。

照合パラメタ (**kwargs) は後述の フィールドの照合 で説明するフォーマッ トにします。複数のパラメタを指定すると、背後の SQL 文では AND で結合さ れ、制約条件節全体を NOT() で囲みます。

以下の例では、 pub_date が 2005 年 1 月 3 日より未来の日時になっていて、 かつ headline が "Hello" で始まる全てのエントリを除外します:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

SQL 用語でいうと、以下のようなクエリの評価になります:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

また、以下の例では、 pub_date が 2005 年 1 月 3 日より未来の日時で あるか、 または headline が "Hello" で始まる全てのエントリを除外しま す:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

SQL 用語でいうと、以下のようなクエリの評価になります:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

二つ目の例の方が厳しい制約になっていることに注意して下さい。

order_by(*fields)

デフォルトでは、 QuerySet の返す結果はモデルの Metaordering オプションに指定した整列条件のタプルに従って整列されます。 order_by を 使うと、この挙動を QuerySet 単位でオーバライドできます。

例えば:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

このクエリの結果は、まず pub_date で降順に並べ、次いで headline で 昇順に並べたものになります。 "-pub_date" の先頭にあるマイナス記号が 降順 表しています。何も指定しないと昇順になります。整列をランダムに したければ、以下のように "?" を使います:

Entry.objects.order_by('?')

注意: order_by('?') を使うと、使っているバックエンドによってはコストの かかる低速なクエリになります。

別のモデル内のフィールドを使ってモデルを整列させるには、モデルのリレーショ ン追跡と同じ構文を使ってフィールドを指定します。すなわち、フィールド名の後 ろにアンダースコア 2 つ (__) 、さらに新たなモデルのフィールド名を続けま す。この調子で、任意の深さまでモデルを追跡できます。例えば:

Entry.objects.order_by('blog__name', 'headline')

他のモデルへのリレーションを使ってモデルインスタンスを整列しようとすると、 Django はリレーション先のモデルのデフォルトの整列順 (Meta.ordering が指 定されていなければプライマリキー) を使います。例えば:

Entry.objects.order_by('blog')

は、 Blog モデルにデフォルトの整列順が指定されていないので、以下のコー ドと同じです:

Entry.objects.order_by('blog__id')

Be cautious when ordering by fields in related models if you are also using distinct(). See the note in the distinct() section for an explanation of how related model ordering can change the expected results.

It is permissible to specify a multi-valued field to order the results by (for example, a ManyToMany field). Normally this won't be a sensible thing to do and it's really an advanced usage feature. However, if you know that your queryset's filtering or available data implies that there will only be one ordering piece of data for each of the main items you are selecting, the ordering may well be exactly what you want to do. Use ordering on multi-valued fields with care and make sure the results are what you expect.

開発版の Django で新たに追加された機能: クエリをデフォルトの整列も含め て一切整列させたくない場合には、 order_by() を引数なしで呼び出してくだ さい。

開発版の Django で新たに追加された機能: リレーションをまたいでモデルを 整列する際の構文が変更されました。 以前の動作は Django 0.96 のドキュメント を参照してください。

大小文字の区別を考慮して整列するかどうかを指定する方法はありません。大小文 字の区別については、 Django は現在使っているデータベースバックエンドの整列 方法に従います。

reverse()

開発版の Django で新たに追加された機能

クエリセットの要素を逆順で返させたい場合は、 reverse() メソッドを使って ください。 reverse() を 2 度呼び出すと、並び順を元の正順に戻します。

例えば、「最新の」 5 要素を取り出すには、以下のようにします:

my_queryset.reverse()[:5]

これは、 Python の配列を末尾部分から数えてスライスするのとは少し違います。 上の例は、最末尾の要素が最初に、最後から 2 つ目は要素を次に、という順序で要 素を返します。Python の配列で seq[-5:] とすると、最後から 5 つめの要素 以降を順に返します。 Django では、 SQL の効率の観点から、このようなアクセス (末尾からの要素数での指定) をサポートしていません。

distinct()

SQL クエリに SELECT DISTINCT を使う新たな QuerySet を返します。 distinct() を使うと、クエリ結果から重複する行をなくします。

デフォルトでは、 QuerySet は重複する行を除去しません。通常は、 Blog.objects.all() のような単純なクエリは重複する行を含むような結果にな らないため、これはあまり問題にはなりません。しかし、クエリが複数のテーブル にわたる場合、 QuerySet の評価結果に重複する結果が入る場合があります。 その場合には distinct() を使って下さい。

Note

order_by() に指定したフィールドは、 SQL レベルで SELECT されま す。そのため、 order_by()distinct() と組み合わせると予期し ない結果を生むことがあります。例えば、リレーション先のモデルフィールド を使って整列を行うと、それらのフィールドも SELECT されるため、 リレーション元のオブジェクトは同じ値で、リレーション先のフィールド値だ けが違うレコードは異なる (distinct) レコードとみなされます。リレーショ ン先のレコードカラムは (順序を制御するために使われるだけなので) 返され ず、その結果、distinct 制約を満たしていないクエリ結果が返されるように見 えてしまいます。

同様に、 values() クエリを使って SELECT 対象のカラムを制約する 場合も、 order_by() に指定したカラム (またはモデルのデフォルトの順 序制御カラム) が自動的にクエリ結果に含められ、結果の一意性に影響を及ぼ します。

distinct() を使う場合、リレーション先のフィールドを使った並べ替えに はよく注意しましょう。同様に、 distinct()values() を同時に 使うときにも、 values() の対象とするフィールドに順序カラムが入って いない場合はよく注意してください。

values(*fields)

ValueQuerySet を返します。 ValueQuerySetQuerySet のサブクラ スで、評価結果としてモデルインスタンスオブジェクトの代りに辞書のリストを返 す QuerySet です。

リスト中の各辞書は個々のオブジェクトを表現しており、キーがモデルオブジェク トの各属性名に、対応しています。

以下の例では、 values() の辞書と通常のモデルオブジェクトを比較していま す:

# リストには Blog オブジェクトが入ります。
>>> Blog.objects.filter(name__startswith='Beatles')
[Beatles Blog]

# リストには辞書が入ります。
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

values() オプションの可変長の引数 *fields を取れます。このオプションは SELECT の制限に使うフィールド名を列挙したものです。 fields を指定し た場合、辞書には指定した名前のフィールドのキーと値だけが入ります。 *fields を指定しなければ、辞書にはテーブルの全てのフィールドのキーと値 が入ります。

例を示します:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

ForeignKey リレーションをまたいで values() を使うには、 filter() コマンドと同様に、フィールド名を二重アンダースコアで区切って指 定します。例えば:

>>> Entry.objects.values('blog__name').distinct()
[{'name': 'Beatles Blog'}]

注意すべき点が 2 つほどあります:

  • values() メソッドに ManyToManyField を渡して結果を得ることは できません。 ManyToManyField 型のフィールドを渡すと、エラーを送出 します。

  • ForeignKey のフィールド foo がモデルに入っている場合、 values() がデフォルトで返す辞書には、 foo_id というキーが入っ ています。これは、リレーションの実際の値が入っているモデル内部の隠し フィールドの名前です (foo はリレーション先のモデルインスタンスを 参照しています)。一方、 values() にフィールド名を指定して呼び出す 場合は、 foofoo_id のどちらでも渡せますが、得られる結果は 同じ (辞書のキーは渡したフィールド名と同じ) で、リレーションの実際の 値です。

    例を以下に示します:

    >>> Entry.objects.values()
    [{'blog_id: 1, 'headline': u'First Entry', ...}, ...]
    
    >>> Entry.objects.values('blog')
    [{'blog': 1}, ...]
    
    >>> Entry.objects.values('blog_id')
    [{'blog_id': 1}, ...]
    
  • values()distinct() を組み合わせて使う場合、カラム値による 並べ替えが結果に思わぬ影響をもたらすことがあります。詳しくは distinct() の節を参照してください。

開発版の Django で新たに追加された機能: 以前は、 values() に渡せる のは blog だけで、 blog_id は使えませんでした。

ValuesQuerySet が便利なのは、わずかな数のフィールドの値しか必要でなく、 モデルインスタンスオブジェクトの機能が必要でないと分かっている場合です。 必要なフィールドだけを選択すると、さらに効率的になります。

最後に、 ValuesQuerySetQuerySet のサブクラスなので、 QuerySet の全てのメソッドを持っている点に注意してください。 ValuesQuerySet に対して filter()order_by() といった操作を行 えます。そう、以下の二つの呼び出しは等価になります:

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

Django の作者たちは、全ての SQL 関係のメソッドを先に配置し、その後に (必要 なら) 出力関係のメソッド (values() など) を配置するやり方を好んでいます。 とはいえ、これは実際上問題ではないので、個人的な信条を反映させてかまいませ ん。

values_list(*fields)

開発版の Django で新たに追加された機能です

values() に似ていますが、辞書のリストを返すのではなく、タプルのリストを 返します。各タプルには values_list() の引数に渡したフィールドの値が、引 数の順番に一致して入っています。例えば:

>>> Entry.objects.values_list('id', 'headline')
[(1, u'First entry'), ...]

フィールドを一つだけ指定する場合、 flat というパラメタも指定できます。 このパラメタを True にすると、結果は 1 要素のタプルではなく一つの値とし て返されます。以下の例を見れば、違いがはっきりするでしょう:

>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]

>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]

複数のフィールドを指定しているときに flat を渡すとエラーを送出します。

values_list() に引数を渡さなければ、モデルの全てのフィールドを定義順に 並べたタプルのリストを返します。

dates(field, kind, order='ASC')

DateQuerySet を返します。 DateQuerySetQuerySet のサブクラス で、評価結果としてクエリセット内のコンテンツの全日付を datetime.datetime オブジェクトとして返す QuerySet です。

field はモデルの DateField または DateTimeField の名前です。

kind"year", "month" または "day" です。 結果リスト中の各 datetime.datetime オブジェクトは type の指定に従っ て切り詰められます。

  • "year" フィールドの年部分の値の重複しないリストを返します。
  • "month" フィールドの年/月部分の値の重複しないリストを返します。
  • "day" フィールドの年/月/日部分の値の重複しないリストを返します。

order には結果の並び順を指定します。デフォルト値は 'ASC' で、 "ASC" または "DESC" にできます。

例を示します:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.datetime(2005, 3, 20)]

none()

開発版の Django で新たに追加された機能です

EmptyQuerySet を返します。 EmptyQuerySet とは、評価結果が常に空の リストになるクエリセットです。関数の戻り値などで空の照合結果を返したいが、 呼び出し側が (空のリストなどではなく) クエリセットオブジェクトの戻り値を期 待している場合に便利です。

例:

>>> Entry.objects.none()
[]

all()

開発版の Django で新たに追加された機能です

クエリセット(またサブクラス)の「コピー」を返します。モデルマネジャやクエ リセットを引数に渡してフィルタ処理を行わせたいような場合に便利です。モデル マネジャもクエリセットも all() を呼び出して、適切なクエリセットを取り出 せるからです。

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

時として、 Django のクエリ表記法だけでは複雑な WHERE 節を容易に表現でき ない場合があります。こうした特異な場合のために、 Django では extra() というクエリセット修飾子を提供しています。このメソッドは、クエリセットが 生成する SQL 文中に特定の SQL 節を挿入するためのフックです。

定義上、これらの拡張照合機能は (直接 SQL コードを書いているため) データベー スエンジン間の可搬性がありません。また、 DRY 則の侵犯でもあります。可能な限 り使わないようにして下さい。

params, select, where, tables のいずれかを指定します。 いずれの引数も必須ではありませんが、少なくとも一つは指定せねばなりません。

select

select キーワードを使うと、 SELECT 節に追加のフィールドを選択で きます。この引数は、属性名とその属性値を計算するための SQL 節を対応づけ た辞書にします。

例えば:

Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})

のようにすると、 Entry オブジェクトは、エントリの pub_date が Jan. 1, 2006 より大きいかどうかを示すブール値の属性 is_recent を 持つようになります。

Django は指定された SQL を直接 SELECT 文に挿入するので、上の例の SQL 文は以下のようになります:

SELECT blog_entry.*, (pub_date > '2006-01-01')
FROM blog_entry;

次の例はもっと高度です。この例では、 Blog オブジェクトに関連づけら れている Entry オブジェクトの個数を表す整数を、 Blog オブジェク トの entry_count 属性に持たせるためにサブクエリを実行しています:

Blog.objects.extra(
    select={
        'entry_count': 'SELECT COUNT(*) FROM blog_entry ' \
                       'WHERE blog_entry.blog_id = blog_blog.id'
    },
)

(上の場合では、クエリの FROM 節に blog_blog が入るという事実を 利用しています。)

上の例の場合、 SQL は以下のようになります:

SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id)
FROM blog_blog;

ほとんどのデータベースエンジンでは、サブセレクションの周りに丸括弧が必 要ですが、Django の select 節では必要ないということに注意してくださ い。また、 MySQL の一部のバージョンのように、データベースバックエンドに よってはサブクエリをサポートしないので注意してください。

開発版の Django で新たに追加された機能 ごく稀に、 extra(select=...) に指定する SQL にパラメタを渡したい場 場合があります。そんなときは select_params パラメタを使ってください。 ただし、 select_params はシーケンス型で、 select は辞書なので、 select= の中でパラメタが正しく一致するように注意する必要があります。 select に通常の辞書型を渡す代わりに django.utils.datastructures.SortedDict を指定すれば、こうした状況を うまく扱えます。

例えば、以下のコードは期待通りに動作します:

Blog.objects.extra(
    select=SortedDict(('a', '%s'), ('b', '%s')),
    select_params=('one', 'two'))
where / tables

明示的に追加の WHERE 節を渡す必要がある場合 -- おそらく非明示的な結 合を行っている場合 -- には、 where キーワードを使って下さい。 tables を使えば、 SQL の FROM 節に手動でテーブル名を追加できま す。

wheretables は、ともに文字列のリストを引数にとります。 where パラメタの内容は全て、多の検索条件と "AND" で結合されます。

例えば:

Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])

は、(大雑把にいって) 以下のような SQL 文に変換されます:

SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);

tables パラメタを使う場合、クエリ中にすでに登場しているテーブルを指 定していないか注意が必要です。 tables パラメタに追加のテーブル名を 指定して、それがすでにクエリ中に含まれているテーブルであった場合、 Django はユーザがそのテーブルをさらに加えようとしているものとみなします。 その場合、追加されたテーブルの名前にはエイリアスがつけられるので、問題 を引き起こします。 SQL 文の中に同じテーブルを複数回登場させる場合、デー タベースがそれぞれのテーブルを区別できるように、2度目以降のテーブル名に はエイリアスをつけねばなりません。そのため、 where パラメタにすでに クエリ中に存在するテーブル名を渡すと、エラーを引き起こすのです。

通常は、すでにクエリ中に存在するテーブル名を追加するような作業はしない はずです。しかし、上で述べたようなことが起きてしまう場合には、いくつか 解決方法があります。まず、追加でテーブル名を指定しなくても正しくクエリ を実行できるか試してください。それがだめなら、クエリセットを構築する際 に、 extra() を先に呼び出して、テーブル名を最初に登場させてみてく ださい。最後に、どうしてもうまくいかないのなら、生成されるクエリを見て、 where を書き直し、テーブル名にエイリアスを与えてみてください。 エイリアスは同じ方法でクエリセットを生成している限り同じ名前を持つので、 エイリアス名は変化しないものとして扱えます。

order_by

クエリセットの評価結果を、 extra() に入れたフィールドやテーブルに基 づいて並べ替えたい場合は、 extra()order_by パラメタを指定し てください。 order_by は文字列のシーケンスで指定します。各文字列は (order_by() メソッドで指定するような) モデルフィールド名か、 table_name.column_name 形式か、 extra()select パラメ タに指定したカラムのエイリアスのいずれかで指定します。

例を示しましょう:

q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
q = q.extra(order_by = ['-is_recent'])

上の例は、 is_recent が真であるような結果を先に表示します (True よりも False が先にくるのは降順のときだからです)。

ちなみに、上の例でわかるように、 extra() は何度も呼び出しできます。 (その度に、制約条件が追加されてゆきます)。

params

上で説明した where パラメタでは、標準の Python の文字列プレースホル ダ '%s' を使って、データベースエンジンが自動的にパラメタをクオート するよう指示できます。 params 引数には、プレースホルダで置き換えら れるパラメタのリストを指定します。

例えば:

Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

where の中に直接値を埋め込まず、常に params を使うようにしてく ださい。というのも、 params を使えば、バックエンド固有の方法でパラ メタの値を正しくクオートするからです。 (例えば引用符文字などを正しくエ スケープします)

悪い例:

Entry.objects.extra(where=["headline='Lennon'"])

良い例:

Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

selectwhere の中に入れるプレースホルダの個数合計と、 params リストに入れる値の個数は一致させねばなりません。

開発版の Django で新たに追加された機能 extra() の引数として、 新たに select_params が追加されました。以前は、 params を使って select のパラメタを渡そうとするしかありませんでしたが、その挙動はあまり 信頼できませんでした。

QuerySet を返さないクエリセットメソッド

以下のクエリセットメソッドは、クエリセットを評価して、クエリセット でない 値を返します。

これらのメソッドはキャッシュを使わず (後述の キャッシュとクエリセット を 参照してください)、メソッド呼び出しごとにデータベースにクエリをかけます。

get(**kwargs)

照合パラメタに一致するオブジェクトを返します。照合パラメタは後述の フィールドの照合 で説明するフォーマットにします。

AssertionError

複数のオブジェクトが見つかった場合、 get()MultipleObjectsReturned を送出します。 MultipleObjectsReturned 例外は、モデルクラスの属性です。例えば、以下の ようなコードで 'John' という名前の作者が複数見つかると、 MultipleObjectsReturned が送出されます:

Author.objects.get(name='John') # raises Author.MultipleObjectsReturned

指定パラメタに対するオブジェクトが見つからなかった場合には DoesNotExist 例外を送出します。 DoesNotExist 例外はモデルクラスの属性の一つです。 例えば:

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

DoesNotExist 例外は django.core.exceptions.ObjectDoesNotExist を継 承しているので、複数の DoesNotExist 例外を except: のターゲットにで きます。例えば:

from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print "Either the entry or blog doesn't exist."

create(**kwargs)

ワンステップでオブジェクトを生成して保存するための便宜メソッドです。 すなわち、以下の文:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

と、以下の文:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save()

は等価です。

get_or_create(**kwargs)

kwargs に指定したオブジェクトを照合し、なければ生成するための便宜メソッドで す。

(object, created) の形式のタプルを返します。 object は取得または作 成されたオブジェクトであり、 created はブール値で、オブジェクトが新たに 生成されたかどうかを示します。

このメソッドは、お決まりのコードを書く上でのショートカットとして定義されて おり、データを取り込むスクリプトを書くときに便利です。例えば:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

このようなコードパターンでは、モデル中のフィールドが増えると手に負えなくな ります。 get_or_create() を使うと、上のコード例は以下のように書き直せま す:

obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
                  defaults={'birthday': date(1940, 10, 9)})

get_or_create() に渡されたキーワード引数は、 (オプションの引数である defaults を除いて) 全て get() の呼び出し時の引数として渡されます。 オブジェクトが見つかった場合、 get_or_create() は見つかったオブジェクト と False を返します。オブジェクトが 見つからなかった 場合、新たに生成 されたオブジェクトと True を返します。新たなオブジェクトは以下のアルゴ リズムで作成されます:

defaults = kwargs.pop('defaults', {})
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()

上のコードを日本語で表すなら、まず 'defaults' でないキーワード引数のう ち、二重アンダースコアを含まないもの (二重アンダースコアはあいまい照合のキー ワードなので除外します) を使ってパラメタ params を作成し、必要に応じて デフォルト値 defaults で内容を更新して、その結果をモデルクラスを呼び出 すときのキーワード引数に使います。

defaults という名前のフィールド名を持っていて、 get_or_create() の 中で厳密照合に使いたければ、以下のように 'defaults__exact' を使います:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

最後に、 Django ビューの中で get_or_create() を使う場合についてひとこと 注意しておきましょう。上で説明したように、主として get_or_create() が有 用なのは、データを解析し、該当する既存のデータが存在しない場合に新たなレコー ドを生成するようなスクリプトを書く場合です。ビューで get_or_create() を 使いたいのなら、特に理由のない限り POST リクエスト中で使うようにしましょ う。一般論として、 GET リクエストの処理中ではデータに影響を及ぼすべきで はありません。データに副作用をもたらすようなページのリクエストには常に POST を使うようにしましょう。詳しくは、 HTTP 仕様における 安全なメソッド を参照してください。

count()

クエリセットに一致するデータベース上のオブジェクトの個数を表す整数を返しま す。 count() は例外を送出しません。

例えば:

# データベース中のエントリの総数を返します。
Entry.objects.count()

# ヘッドラインが 'Lennon' を含むエントリの総数を返します。
Entry.objects.filter(headline__contains='Lennon').count()

count() は背後で SELECT COUNT(*) を実行するので、単にオブジェクトの 個数を数えたい場合には、全てのレコードを Python オブジェクトとしてロードし てから len() を呼び出すのではなく、常に count() を使うようにしてく ださい。

(PostgreSQL や MySQL といった) どのデータベースを使っているかによって、戻り 値が Python の通常の整数型ではなく、長整数になることもあります。これは実装 上の問題であり、現実的に問題になることはありません。

in_bulk(id_list)

主キーの値のリストを引数にとり、各主キー値とオブジェクトを対応づけた辞書を 返します。

例えば:

>>> Blog.objects.in_bulk([1])
{1: Beatles Blog}
>>> Blog.objects.in_bulk([1, 2])
{1: Beatles Blog, 2: Cheddar Talk}
>>> Blog.objects.in_bulk([])
{}

in_bulk() に空のリストを渡すと空の辞書を返します。

iterator()

QuerySet を評価し (クエリを実行し) て、その結果の入った イテレータ を返します。 QuerySet は通常、最初にアクセスした時点で、全ての検索結果 を読み込んで、対応するオブジェクトのインスタンスを生成してしまいます。 一方、 iterator() は、離散的なチャンク単位で検索結果を読み出し、オブジェ クトをインスタンス化して、一度に一つづつ yield します。 QuerySet は膨大 な数のオブジェクトを返す場合があるので、その場合には iterator() を使う ことでパフォーマンスを改善し、メモリの使用量を劇的に減らせます。

すでに値にアクセス済みの QuerySet に対して iterator() を呼び出すと、 値の評価が再度行われ、クエリが繰り返し発行されるので注意してください。

latest(field_name=None)

日付フィールドである field_name の値に応じて、テーブル中の最新のオブジェ クトを返します。

以下の例では、 pub_date フィールドに応じて、テーブル中の最新の Entry を返します:

Entry.objects.latest('pub_date')

モデルの Metaget_latest_by を指定している場合、 latest()field_name 引数は省略できます。 Django は get_latest_by に指定し たフィールドをデフォルト値にします。

get() と同様、 latest() は指定パラメタに一致するオブジェクトがない 場合に DoesNotExist を送出します。

latest() は純粋に利便性と可読性のためだけに存在しています。

フィールドの照合

フィールドの照合は、 SQL の WHERE 節の中身を決めます。フィールド照合は、 filter(), exclude() および get() といったクエリセットのメソッド のキーワード引数として指定します。

基本的に、照合のキーワード引数名は field__lookuptype=value のような形 式をとります (アンダースコアは二重です)。例えば:

Entry.objects.filter(pub_date__lte='2006-01-01')

は、(大雑把にいって) 以下のような SQL 文に変換されます:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

フィールド検索のからくり

Python には、任意の名前と値をもった引数を受け取れる関数を定義する機能が あり、引数名とその値は実行時に評価されます。くわしい情報は公式の Python チュートリアルの キーワード引数 を参照してください。

無効なキーワード引数を渡した場合、 TypeError を送出します。

データベース API では、以下の照合タイプをサポートしています:

exact

厳密な一致です、比較対象の値を None にすると、SQL における NULL と の比較として扱われます (詳しくは isnull を参照してください)。

例:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

等価な SQL 文:

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

開発版の Django で新たに追加された機能: 開発版では、 id__exact=None のセマンティクスが変更されました。以前は SQL レベルで (意図的に) WHERE id = NULL に置き換えられていましたが、この SQL はいかなるレコード にもマッチしません。開発版では、 id__isnull=True と同じ挙動を示すように 変更されています。

iexact

大小文字の区別をしない一致です。

例:

Blog.objects.get(name__iexact='beatles blog')

等価な SQL 文:

SELECT ... WHERE name ILIKE 'beatles blog';

この例は、 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG' などにマッチします。

contains

大小文字を区別する包含テストです。

例:

Entry.objects.get(headline__contains='Lennon')

等価な SQL 文:

SELECT ... WHERE headline LIKE '%Lennon%';

この例では、 'Today Lennon honored' というヘッドラインには一致しますが、 'today lennon honored' には一致しません。

SQLite は大小文字を区別する LIKE をサポートしないので、 containsicontains と同じになります。

icontains

大小文字を区別しない包含テストです。

例:

Entry.objects.get(headline__icontains='Lennon')

等価な SQL 文:

SELECT ... WHERE headline ILIKE '%Lennon%';

gt

より大きい値に一致します。

例:

Entry.objects.filter(id__gt=4)

等価な SQL 文:

SELECT ... WHERE id > 4;

gte

等しいか、より大きい値に一致します。

lt

より少ない値に一致します。

lte

等しいか、より少ない値に一致します。

in

指定のリストに入っているものに一致します。

例:

Entry.objects.filter(id__in=[1, 3, 4])

等価な SQL 文:

SELECT ... WHERE id IN (1, 3, 4);

リテラル値のリストを渡す代わりに、クエリセットを使って動的なリストとして評 価してもかまいません。クエリセットは values() メソッドを使って個々のオ ブジェクト値からなるリストに変換できねばならず、 query 属性を使ってクエ リセットに変換してから渡さねばなりません:

Entry.objects.filter(blog__in=Blog.objects.filter(name__contains='Cheddar').values('pk').query)

上のクエリセットを評価すると、以下の SQL 文のようになります:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

startswith

大小文字を区別する starts-with です。

例:

Entry.objects.filter(headline__startswith='Will')

等価な SQL 文:

SELECT ... WHERE headline LIKE 'Will%';

SQLite は大小文字を区別する LIKE をサポートしないので、 startswithistartswith と同じになります。

istartswith

大小文字を区別しない starts-with です。

例:

Entry.objects.filter(headline__istartswith='will')

等価な SQL 文:

SELECT ... WHERE headline ILIKE 'Will%';

endswith

大小文字を区別する ends-with です。

例:

Entry.objects.filter(headline__endswith='cats')

等価な SQL 文:

SELECT ... WHERE headline LIKE '%cats';

SQLite は大小文字を区別する LIKE をサポートしないので、 endswithiendswith と同じになります。

iendswith

大小文字を区別しない ends-with です。

例:

Entry.objects.filter(headline__iendswith='will')

等価な SQL 文:

SELECT ... WHERE headline ILIKE '%will'

range

範囲テスト (閉包テスト) です。

例:

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

等価な SQL 文:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

range は日付、数値、文字など、SQL で BETWEEN を使える場所ならどこで も使えます。

year

date/datetime フィールドにおける、 year の厳密一致です。

例:

Entry.objects.filter(pub_date__year=2005)

等価な SQL 文:

SELECT ... WHERE EXTRACT('year' FROM pub_date) = '2005';

(厳密な SQL シンタクスはデータベースエンジンによって違います。)

month

date/datetime フィールドにおける、 month の厳密一致です。 1 (1月) から 12 (12 月) までの整数を引数にとります。

例:

Entry.objects.filter(pub_date__month=12)

等価な SQL 文:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';

(厳密な SQL シンタクスはデータベースエンジンによって違います。)

day

date/datetime フィールドにおける、 day の厳密一致です。

例:

Entry.objects.filter(pub_date__day=3)

等価な SQL 文:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';

(厳密な SQL シンタクスはデータベースエンジンによって違います。) このクエリ文は、「1 月 3 日」や「7 月 3 日」のように、毎月 3 日、にマッチし ます。

isnull

True または False を引数にとり、それぞれが IS NULL および IS NOT NULL に対応しています。

例:

Entry.objects.filter(pub_date__isnull=True)

等価な SQL 文:

SELECT ... WHERE pub_date IS NULL;

regex

開発版の Django で新たに追加された機能です

正規表現による大小文字を区別した検索を行います。

正規表現の構文は各データベースバックエンドで使われているものと同じです。 正規表現による照合をサポートしない sqlite バックエンドの場合に、Python の re モジュールと同じ構文を使います。

使い方の例を示します:

Entry.objects.get(title__regex=r'^(An?|The) +')

同じ意味の SQL 文は以下のようになります:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

正規表現を指定する場合には raw 文字列を使う ('foo' でなく r'foo' を 使う)よう勧めます。

iregex

開発版の Django で新たに追加された機能です

正規表現による大小文字を区別しない検索を行います。

使い方の例を示します:

Entry.objects.get(title__iregex=r'^(an?|the) +')

同じ意味の SQL 文は以下のようになります:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

デフォルトの照合形式は exact

照合形式 (lookup type) を指定しない場合、つまりキーワード引数に二重アンダー スコアが入っていない場合は、照合形式は exact であるとみなされます。

例えば、以下の二つの文は等価です:

Blog.objects.get(id__exact=14) # 明示的な形式
Blog.objects.get(id=14) # 暗黙で __exact を表す

これは exact 照合がよくある形式であることによる便宜的なものです。

pk 照合ショートカット

利便性のために、 Django には pk という照合形式があります。 pkprimary_key を表します。

Blog モデルの例では、主キーは id フィールドなので、以下の二つの文は 等価になります:

Blog.objects.get(id__exact=14) # 明示的な形式
Blog.objects.get(id=14) # 暗黙で __exact を表す
Blog.objects.get(pk=14) # pk は暗黙で id__exact を表す

pk__exact のクエリにしか使えないわけではありません。どのクエリ 用キーワードも pk と組み合わせてかまいません。 pk を使ったクエリは、 モデルの主キーに対するクエリになります。

# id が 1, 4 および 7 のブログエントリを取得する Blog.objects.filter(pk__in=[1,4,7]) # id > 14 の全てのブログエントリを取得する Blog.objects.filter(pk__gt=14)

pk による検索は join 越しでも行えます。 例えば、以下の二つの文は等価で す:

Entry.objects.filter(blog__id__exact=3) # 明示的な形式
Entry.objects.filter(blog__id=3) # 暗黙で __exact を表す
Entry.objects.filter(blog__pk=3) # __pk は暗黙で __id__exact を表す

Note

このショートカットを実現するため、モデルには pk という名前のフィー ルドを定義できません。 pk は、クエリ中では常にモデルの主キーに置き 換えられます。

リレーションをまたいだ照合

Django では、背後で自動的に SQL JOIN を処理し、照合の際にリレーションを 「追跡」する、強力でありながら直感的な手段を提供しています。リレーションを またぐには、二重アンダースコアを使ってリレーションの張られたフィールドのフィー ルド名を指定します。リレーション間のスパンは、目的のフィールドに到達するま でいくらでも連鎖させられます。

以下の例では、 name'Beatles Blog' であるような BlogEntry エントリオブジェクト全てを取得します:

Entry.objects.filter(blog__name__exact='Beatles Blog')

スパンは好きなだけ深く張れます。

リレーションのスパンは逆方向にも張れます。「逆方向の」リレーションを参照す るには、モデル名を小文字にした名前を使います。

以下の例では、 headline'Lennon' を含むような Entry を少なく とも一つ持つような全ての Blog オブジェクトを取得します:

Blog.objects.filter(entry__headline__contains='Lennon')

多値のリレーションをスパンする

開発版の Django で新たに追加された機能です

ManyToManyFieldForeignKey の逆リレーションを使ってフィルタを行 う場合、 2 種類の異なるフィルタ方法があります。 Blog / Entry のリレー ション (Blog から Entry が 1 対多であるようなリレーション) を考えて みましょう。このようなモデルでは、例えばヘッドラインに 'Lennon' を含み、 かつ 今日公開されたエントリを持つようなブログを検索したい場合があるでしょ う。あるいは、ヘッドラインに 'Lennon' を含むか、 あるいは 今日公開さ れたエントリを含むようなブログの検索もあり得ます。複数のエントリが一つの Blog に関連付けられているので、いずれのクエリも実行可能ですし、意味をな す場合があるでしょう。

ManyToManyField を使っている場合にも、同じような状況が起こります。例え ば、 Entrytags という名前の ManyToManyField があり、 'music''band' というタグに関連付けられたエントリを検索したい場合や、 'music' タグのついた 'public' 状態のエントリを取り出したい場合があるで しょう。

こうした状況をうまく扱うために、 Django には filter() および exclude() といった呼び出しがあります。 filter() に指定した条件は同 時に適用され、条件全てに一致する要素をフィルタします。 filter() を連続 して呼び出すと、通常はオブジェクトの集合により狭い制約をかけますが、多値リ レーションの場合、新たな制約は、前の filter() で絞り込んだリレーション 先をさらに絞り込むのではなく、前の filter() で絞り込んだリレーション先 にリンクしているリレーション元からリレーションを張られている全てのオブジェ クトに対して適用されてしまいます。

この話はちょっとややこしいので、例を挙げて解説しましょう。 'Lennon' をヘッ ドラインに含み、今日公開されたエントリを含むブログを選択するには、以下の ように書きます:

Blog.objects.filter(entry__headline__contains='Lennon',
        entry__pub_date=datetime.date.today())

一方、 'Lennon' をヘッドラインに含むか、 あるいは 今日公開されたエン リを含むブログを検索するには、以下のように書きます:

Blog.objects.filter(entry__headline__contains='Lennon').filter(
        entry__pub_date=datetime.date.today())

後者の例では、最初の filter() でクエリセットに制約をかけ、特定のエント リにリンクを持つブログだけを取り出しています。次の filter() では、取り 出した Blog オブジェクトから、 さらに 二つ目の条件に合うものに制約を かけています。従って、二つ目の filter() で制約をかけている対象の entry は、最初のフィルタで絞り込んだエントリと同じとも、違うとも言い切 れません。一つめの filter() でフィルタしているのはあくまでも Blog であって、 Entry ではないからです。

この挙動は、 exclude() にもあてはまります。一つの exclude() に指定 した条件は、 (多値リレーションの場合は) 各インスタンスに同時に適用されます。 filter()exclude() を連続して呼び出すと、毎回違うリンク先集合を 使ってフィルタを行ってしまう可能性があるのです。

LIKE 文におけるパーセント記号とアンダースコアのエスケープ

LIKE を使う SQL 文になるようなフィールド照合メソッド (iexact, contains, icontains, startswith, istartswith, endswith, iendswith) では、 LIKE 文で使われる二つの特殊な文字、すなわちパーセ ント記号とアンダースコアを自動的にエスケープします。 (LIKE 文では、パー セント記号は任意の複数文字に対するワイルドカードを表し、アンダースコアは任 意の一文字に対するワイルドカードを表します。)

この機能によって、照合操作を直感的に行え、データベースの抽象化を守れます。 例えば、パーセント記号を含むようなエントリ全てを取得したければ、以下のよう にパーセント記号をそのまま使います:

Entry.objects.filter(headline__contains='%')

Django はクオートの処理に気を配ってくれます。 SQL は以下のような感じになり ます:

SELECT ... WHERE headline LIKE '%\%%';

アンダースコアについても同じようなエスケープを行います。パーセント記号とア ンダースコアはいずれも透過的に処理されます。

キャッシュとクエリセット

データベースへのアクセスを最小限にとどめるため、クエリセット各々にはキャッ シュがあります。効率的なコードを書く上で、キャッシュのからくりを理解してお くのは重要なことです。

クエリセットが新たに生成された時点では、キャッシュは空です。クエリセットを 最初に評価したとき (すなわち、データベースへのクエリが最初に生じたとき)、 Django はクエリ結果をクエリセットオブジェクト内のキャッシュに保存し、明示的 にリクエストした結果だけ (例えば、クエリセットに対してイテレーション操作を する場合には、結果セットの最初の要素) を返します。それ以後は、クエリセット を際利用するとキャッシュ済みの結果を返します。

このキャッシュの挙動をよく覚えておいて下さい。というのも、クエリセットを正 しく扱わないと、おもわぬところで手を噛まれるはめになるからです。例えば、以 下の例では二つのクエリセットを作成し、値を評価して、すぐにクエリセットを捨 ててしまっています:

print [e.headline for e in Entry.objects.all()]
print [e.pub_date for e in Entry.objects.all()]

これはすなわち全く同じデータベースクエリが二度実行され、データベースの負荷 を倍加させることを示します。また、 Entry は二つのリクエストを処理する間 にも追加されたり削除されたりする可能性があるため、二つのリストには必ずしも 同じデータベースレコードが入っているとは限りません。

こうした問題を避けるには、クエリセットを保存して再利用してください:

queryset = Poll.objects.all()
print [p.headline for p in queryset] # クエリセットを評価します。
print [p.pub_date for p in queryset] # キャッシュの値を再利用します。

オブジェクトの比較

二つのモデルオブジェクトを比較するには、標準の Python 比較演算子、すなわち 二重等号符: == を使います。背後では二つのモデルオブジェクト間の主キー値 が比較されます。

上の Entry の例では、以下の二つの文は等価になります:

some_entry == other_entry
some_entry.id == other_entry.id

モデルの主キーが id という名前でなくても問題はありません。どのような名 前であれ、比較は常に主キーを使って行われます。例えば、モデルの主キーのフィー ルド名が name であれば、以下の二つの文は等価になります:

some_obj == other_obj
some_obj.name == other_obj.name

Q オブジェクトを使った複雑な照合

filter() などで複数のキーワード引数を指定してクエリを行うと、各々のキー ワード引数の表す照合条件は違いに "AND" で結ばれます。より複雑なクエリ (例え ば OR を使ったクエリ) を実行する必要がある場合には Q オブジェクトを 使えます。

Q オブジェクト (django.db.models.query.Q) は、複数のキーワード引数 をカプセル化するために使われます。キーワード引数は前述の フィールドの照合 で説明したものと同じです。

例えば、以下の Q オブジェクトは単一の LIKE クエリをカプセル化してい ます:

Q(question__startswith='What')

Q オブジェクトは &| といった演算子で組み合わせられます。演 算子で結ばれた二つの Q オブジェクトは新たな Q オブジェクトになりま す。

例えば、以下の文は二つの question__startswith クエリを "OR" したものを 表す単一の Q オブジェクトになります:

Q(question__startswith='Who') | Q(question__startswith='What')

この Q オブジェクトは以下の WHERE 節と同じになります:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

Q オブジェクトを &| で組み合わせれば、好きなだけ複雑なクエ リ文を作成できます。丸括弧を使ったグルーピングも可能です。

開発版の Django で新たに追加された機能: ~ 演算子を使って、 Q オ ブジェクトの否 (negation) を取れるようになりました。この機能を使えば、以下 のように、通常のクエリと否を取った (NOT の) クエリを組み合わせられます:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

キーワード引数をとる照合関数 (filter(), exclude(), get() など) には、複数の Q を固定引数として (名前なしの引数として) 渡せます。複数の Q オブジェクトを照合関数に渡した場合、それらは互いに "AND" で結ばれます。 例えば:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

は、だいたい以下のような SQL になります:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

照合関数は Q オブジェクトとキーワード引数を混ぜて使えます。照合関数に渡 した全ての引数は (キーワード引数も Q オブジェクトも) 互いに "AND" で結 ばれます。ただし、 Q を指定する場合はどのキーワード引数よりも前に指定せ ねばなりませんたとえば:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

は有効なクエリで、前の例と同じになりますが、以下の文:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

は無効です。

OR lookups examples page の例も参照してください。

リレーション

モデル内でリレーション (ForeignKey, OneToOneField, ManyToManyField) を定義すると、そのモデルのインスタンスはリレーション先 のオブジェクトにアクセスするための便利な API を持つようになります。

このドキュメントの冒頭のモデルを例にとると、 Entry オブジェクト e は、 e に関連づけられている Blog オブジェクトに blog という属性 を使って e.blog のようにアクセスできます。

(舞台裏では、この機能は Python の デスクリプタ を使って実装されています。 だからどうだというわけではありませんが、興味のある人のためにここで指摘して おきます。)

Django はまた、リレーションの「相手側」へのアクセス API、すなわちリレーショ ンを張られた側からリレーションを張った側のモデルへのリンクも作成します。例 えば、 Blog オブジェクト b は、リレーションを張った全ての Entry オブジェクトのリストに entry_set 属性を使って b.entry_set.all() の ようにアクセスできます。

この節での例は、全て冒頭に示した Blog Blog, Author, Entry のモデルを使っています。

一対多のリレーション

順方向

モデルに ForeignKey フィールドがある場合、そのモデルのインスタンスは、 単に属性を使ってリレーション先 (外部) のオブジェクトを参照できます。

例:

e = Entry.objects.get(id=2)
e.blog # リレーション先の Blog オブジェクトを返します。

外部キー属性の値は取得 (get) も設定 (set) もできます。当然ながら、外部キー への変更は save() を呼び出すまでデータベースに反映されません。

例:

e = Entry.objects.get(id=2)
e.blog = some_blog
e.save()

ForeignKey フィールドに null=True が設定されていた場合 (NULL 値 を許している場合)、以下の例のように None を代入できます:

e = Entry.objects.get(id=2)
e.blog = None
e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

一対多のリレーションにおける順方向のアクセスは、リレーション先のオブジェク トに最初にアクセスした際にキャッシュされます。それ以降のアクセスでは、同じ オブジェクトインスタンスの外部キーへのアクセスはキャッシュされた値を返しま す。例えば:

e = Entry.objects.get(id=2)
print e.blog  # データベースを検索して、関連づけられた Blog を返します。
print e.blog  # データベースは検索せず、キャッシュを使います。

クエリセットのメソッド select_related() を使うと、一対多のリレーション のリレーション先オブジェクト全てをあらかじめ再帰的にキャッシュに取り込みま す。例えば:

e = Entry.objects.select_related().get(id=2)
print e.blog  # Doesn't hit the database; uses cached version.
print e.blog  # Doesn't hit the database; uses cached version.

select_related() のドキュメントは、前述の 「 新たなクエリセットを返すクエリセットメソッド 」の節にあります。

逆方向

あるモデルが ForeignKey で別のモデルにリレーションを張っている場合、リ レーションを張られた側のモデルのインスタンスは、リレーションを張った側のモ デルの全てのインスタンスを返すマネジャにアクセスできるようになります。リレー ションを張っている側のモデル名を全て小文字にしたものを FOO とすると、マ ネジャの名前のデフォルト値は FOO_set になります。このマネジャはクエリセッ トを返します。クエリセットには前述の「オブジェクトの取得」の節で説明したフィ ルタや操作を行えます。

例:

b = Blog.objects.get(id=1)
b.entry_set.all() # Blog に関連づけられた全ての Entry を返します。

# b.entry_set はクエリセットを返すマネジャです。
b.entry_set.filter(headline__contains='Lennon')
b.entry_set.count()

ForeignKey を定義するときに related_name パラメタを設定しておくと、 FOO_set の名前をオーバライドできます。例えば、 Entry モデルの定義を blog = ForeignKey(Blog, related_name='entries') のように改めると、上の コード例は以下のようになります:

b = Blog.objects.get(id=1)
b.entries.all() # Blog に関連づけられた全ての Entry を返します。

# b.entries はクエリセットを返すマネジャです。
b.entries.filter(headline__contains='Lennon')
b.entries.count()

ForeignKey のマネジャへの逆のアクセスはできません。 ForeignKey はイ ンスタンスとしてアクセスせねばなりません。例えば:

# AttributeError: "Manager must be accessed via instance" を送出します。
Blog.entry_set

前述の「オブジェクトの取得」で説明したクエリセットのメソッドに加えて、 ForeignKey を介したマネジャは以下の追加のメソッドを備えています:

  • add(obj1, obj2, ...): 指定のモデルオブジェクトをリレーション先オ ブジェクトのセットに加えます。

    例:

    b = Blog.objects.get(id=1)
    e = Entry.objects.get(id=234)
    b.entry_set.add(e) # Associates Entry e with Blog b.
    
  • create(**kwargs): 新たなオブジェクトを作成し、保存して、リレーショ ン先オブジェクトのセットに加えます。作成したオブジェクトを返します。

    例:

    b = Blog.objects.get(id=1)
    e = b.entry_set.create(headline='Hello', body_text='Hi',
        pub_date=datetime.date(2005, 1, 1))
    # 自動的に save() されるので、 e.save() を呼ぶ必要はありません。
    

    これは以下の操作と同じです (ただし前者の方が簡潔です):

    b = Blog.objects.get(id=1)
    e = Entry(blog=b, headline='Hello', body_text='Hi',
        pub_date=datetime.date(2005, 1, 1))
    e.save()
    

    モデルからオブジェクトを作成するときに、リレーションを定義するための キーワード引数を必要としないことに注意して下さい。上の例では、 create()blog パラメタを渡していません。 Django は Entry オブジェクトの blog フィールドの値が b であることを 自分で判別します。

  • remove(obj1, obj2, ...): リレーション先オブジェクトのセットから、 指定のオブジェクトを除去します。

    例:

    b = Blog.objects.get(id=1)
    e = Entry.objects.get(id=234)
    b.entry_set.remove(e) # Blog b から Entry e を除去します。
    

    データベースの一貫性を壊さないようにするため、このメソッドは null=True である ForeignKey オブジェクトでしか使えません。リ レーション先のフィールドを None (NULL) にできない場合、あるオ ブジェクトを削除しようとしたときに、必ず何らかの別のオブジェクトに追 加せねばならなくなるからです。上の例では、 b.entry_set() から e を除去する操作は e.blog = None と同じになり、 外部キー blognull=True でないために無効な操作になります。

  • clear(): リレーション先オブジェクトのセットから全てのオブジェクト を除去します。

    例:

    b = Blog.objects.get(id=1)
    b.entry_set.clear()
    

    リレーション先のオブジェクト全てを削除するわけではありません。単にリ レーションを解除するだけです。

    remove()clear() と同様、 null=True であるような外部キー でしか使えません。

リレーション先セットのメンバを一括で代入するには、イテレーション可能オブジェ クトを代入します。例えば:

b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]

clear() メソッドを利用できる場合、イテレーション可能オブジェクト (上の 例ではリスト) からオブジェクトを entry_set に追加する前に、代入先のセッ トに既に存在するオブジェクトを全て除去します。 clear() メソッドを利用 できない 場合、既に存在するオブジェクトを削除せず、単にイテレーション可能 オブジェクト上の全てのオブジェクトを追加します。

この節で説明した「逆方向の」操作は、いずれもデータベースを即時変更します。 操作結果は追加、新規作成、削除といった操作を行う度に即座に自動的にデータベー スに保存されます。

一対一のリレーション

一対一 (one-to-one) のリレーションは多対多のリレーションと非常によく似てい ます。モデルに OneToOneField を定義すると、モデルのインスタンスはリレーショ ン先のオブジェクトを簡単な属性アクセスで参照できます。

例を示します:

class EntryDetail(models.Model):
    entry = models.OneToOneField(Entry)
    details = models.TextField()

ed = EntryDetail.objects.get(id=2)
ed.entry # リレーション先の Entry オブジェクトを返します。

多対多との違いは、逆参照のクエリです。多対多の時と同様、リレーション先のモ デルはリレーション元のモデルに対するマネジャオブジェクトにアクセスできます が、このマネジャはオブジェクトの集合ではなく単一のオブジェクトを表現してい ます:

e = Entry.objects.get(id=2)
e.entrydetail # リレーション先の EntryDetail オブジェクトを返します。

逆リレーション先のオブジェクトが存在しなければ、 Django は DoesNotExist 例外を送出します。

逆参照のリレーションにインスタンスを代入すると、準参照のリレーションと同じ ようにリレーション先を変更できます:

e.entrydetail = ed

多対多のリレーション

多対多のリレーションの場合、リレーションの関係にあるモデルの一方は、互いに もう一方にアクセスするための自動 API を獲得します。この API は一対多のリレー ションにおける「逆方向の」参照のように動作します。前述の 逆方向 を参照し てください。

一対多のリレーションとの唯一の違いは、属性の名前づけ規則です。 ManyToManyField を定義した側のモデルはフィールド名をそのまま使いますが、 「反対側の」モデルでは、相手のモデルのモデル名を小文字にして、 '_set' を追加したもの (一対多のリレーションにおける逆方向の参照と同じ) になります。

例を使って説明した方が理解しやすいでしょう:

e = Entry.objects.get(id=3)
e.authors.all() # Entry の全ての Author オブジェクトを返します。
e.authors.count()
e.authors.filter(name__contains='John')

a = Author.objects.get(id=5)
a.entry_set.all() # Author の全ての Entry オブジェクトを返します。

ForeignKey と同様、 ManyToManyField には related_name パラメタ を指定できます。 上の例で、 EntryManyToManyFieldrelated_name='entries' を指定していた場合、 Author インスタンスは entry_set ではなく entries という属性を持つようになります。

リレーションの後方参照はどうやって実現されているのか

他のオブジェクトリレーショナルマッパでは、双方向からリレーションを定義せね ばなりません。 Django の開発者たちはこれを DRY 則 (Don't Repeat Yourself) の侵犯だと考えたため、 Django では片方だけでリレーションを定義すればよいよ うにしています。

しかし、なぜあるモデルクラスが、自分に対してリレーションを張っているモデル クラスのことを、そのクラスがロードされる前に検知できるのでしょうか?

答えは INSTALLED_APPS 設定にあります。最初にモデルをロードした時に、 Django は INSTALLED_APPS の全てのモデルを走査して、必要に応じて後方参照 をメモリ中に作成します。 INSTALLED_APPS の本質的な機能の一つは、 Django にモデルドメインの全体像を知らせることなのです。

リレーション先オブジェクトを使ったクエリ

リレーション先のオブジェクトを照合条件に含むクエリは、通常の値のフィールド の入ったくえりと同じような規則に従います。クエリにマッチ条件として値を指定 する場合、オブジェクトのインスタンス自体か、オブジェクトの主キー値のいずれ かを使えます。

例えば、 id=5 であるようなBlog オブジェクト b に対しては、以下の三 つのクエリはすべて等価になります:

Entry.objects.filter(blog=b) # オブジェクトインスタンスを使ったクエリ
Entry.objects.filter(blog=b.id) # インスタンスの id を使ったクエリ
Entry.objects.filter(blog=5) # id を直接使ったクエリ

オブジェクトの削除

削除用のメソッドには、便宜的に delete() という名前が付いてます。このメ ソッドはオブジェクトをただちに削除し、戻り値を返しません。例えば:

e.delete()

複数のオブジェクトの一斉削除も可能です。 QuerySet には delete() メソッドがあり、 QuerySet の全てのメンバを削除します。

例えば、 pub_date が 2005 年の Entry オブジェクトを全て削除するには 以下のようにします:

Entry.objects.filter(pub_date__year=2005).delete()

Django は、オブジェクトを削除する際に、SQLでいう ON DELETE CASCADE 制約 をエミュレートします。すなわち、削除対象のオブジェクトを指すような外部キー を持つ全てのオブジェクトも同時に削除されるのです。:

b = Blog.objects.get(pk=1)
# 次の命令は、 Blog と Blog を指す Entry 全てを削除してしまいます。
b.delete()

delete()QuerySet のメソッドにすぎず、 Manager 自体には公開 されていないので注意してください。これは誤って Entry.objects.delete() を実行して 全ての エントリを削除してしまわないようにするための安全機構で す。本当に全てのオブジェクトを削除 したい のなら、以下のように明示的に全 てのオブジェクトを表すクエリセットをリクエストしてください:

Entry.objects.all().delete()

... _Updating multiple objects at once:

複数のオブジェクトを一度に更新する

開発版の Django で新たに追加された機能です

クエリセットが表現する全てのオブジェクトのあるフィールドに特定の値を指定し たいような場合があります。 update() メソッドを使えば、この処理を実現で きます。例えば:

# pub_date が 2007 の全エントリのヘッドラインを更新する
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

この操作を行えるのは、リレーションフィールドでないフィールドか、 ForeignKey のフィールドのみです。また、フィールドに指定する値はハードコー ドされた Python の値でなければなりません (つまり、その時の何らかのフィール ド値は直接セットできません)。

ForeignKey のフィールドを更新するには、以下のように、新たなモデルインス タンスを作成して渡します:

b = Blog.objects.get(pk=1)
# 全てのエントリをこの blog に属させる
Entry.objects.all().update(blog=b)

update() メソッドは (delete() と同様)、即座に適用され、値を返しませ ん。また、更新対象のクエリセットには、モデルの主のテーブル一つに対してし かアクセスできないという制限があります。従って、クエリセットを構築するとき に、リレーション先のフィールドでフィルタしたりしてはなりません。複数のテー ブルを操作するようなクエリセットに対しては、 update() は動作しません。

update() メソッドは SQL 文に直接変換されるので注意してください。このメ ソッドは、フィールド値の直接更新を大量一括実行するためのものです。 モデルの save() メソッドを呼出さないので、 (save() の呼び出しに連動 している) pre_savepost_save といったシグナルは発生しません。 クエリセット内の全ての要素に対して save() メソッドを適用したければ、 単に全要素に渡って save() を呼び出してください:

for item in my_queryset:
    item.save()

追加のインスタンスメソッド

save(), delete() に加えて、モデルオブジェクトは以下のいずれか、あるい は全てのメソッドを持つことがあります:

get_FOO_display()

choices セットを持つ全てのフィールドについて、オブジェクトは get_FOO_display() メソッドを持ちます。 FOO はフィールド名です。この メソッドは、「人間可読な」フィールド名を返します。例えば、以下のモデル:

GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
class Person(models.Model):
    name = models.CharField(max_length=20)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

では、各 Person インスタンスは get_gender_display() メソッド を持ちます:

>>> p = Person(name='John', gender='M')
>>> p.save()
>>> p.gender
'M'
>>> p.get_gender_display()
'Male'

get_next_by_FOO(**kwargs) and get_previous_by_FOO(**kwargs)

null=True であるような DateField および DateTimeField フィール ドについて、オブジェクトは get_next_by_FOO() および get_previous_by_FOO() メソッドを持ちます。 FOO はフィールド名です。 このメソッドは該当の日付フィールドに応じて前のオブジェクトや次のオブジェク トを返します。適切なオブジェクトがなければ DoesNotExist を送出します。

これらのメソッドはいずれもオプションのキーワード引数をとります。引数は 前述の「フィールド検索」で解説した形式にします。

同じ日付値を持つオブジェクトがある場合、このメソッドは ID を使ったチェック にフォールバックします。これにより、レコードがスキップしたり重複したりしな いことが保証されています。完全なコードの例は 照合 API のサンプルモデル を参照してください。

get_FOO_filename()

FileField につき、オブジェクトは get_FOO_filename() メソッドを持 ちます。 FOO はフィールド名です。このメソッドは、 MEDIA_ROOT の設定 に基づいてファイルのファイルシステム上での完全なパスを返します。

Note

このメソッドの戻り値が正しい値を示すのは、フィールドに値をセットしてセー ブした です。セーブ前にこのメソッドを呼び出しても、戻り値のパス には (フィールドの upload_to パラメタに指定した) アップロードディレ クトリが入っていません。

ImageField は技術的に FileField のサブクラスであるため、 ImageField のフィールドを持つ全てのモデルはこのメソッドを使えます。

get_FOO_url()

FileField につき、オブジェクトは get_FOO_url() メソッドを持ちま す。 FOO はフィールド名です。このメソッドは、 MEDIA_URL の設定に基づ いてファイルの完全な URL を返します。フィールドの値が空の場合、空文字列を返 します。

Note

get_fOO_filename() と同様、このメソッドの戻り値が正しい値を示すのは、 フィールドに値をセットしてセーブした です。セーブ前は、正しい値 を返しません。

get_FOO_size()

FileField につき、オブジェクトは get_FOO_filename() メソッドを持 ちます。 FOO はフィールド名です。このフィールドはファイルのサイズをバイ トを単位として返します (背後では os.path.getsize を使っています)。

save_FOO_file(filename, raw_contents)

FileField につき、オブジェクトは get_FOO_filename() メソッドを持 ちます。 FOO はフィールド名です。このメソッドは指定のファイルを指定のファ イル名でファイルシステムに保存します。指定されたファイル名のファイルがすで に存在する場合、 Django は同名のファイルが見つからなくなるまでファイル名の 末尾 (かつ、拡張子よりも前) にアンダースコアを追加してゆきます。

get_FOO_height() and get_FOO_width()

ImageField につき、オブジェクトは get_FOO_width() および get_FOO_width() メソッドを持ちます。 FOO はフィールド名です。このメ ソッドは画像の高さ (や幅) をピクセルを単位とする整数で返します。

ショートカット用の関数

ビューを開発していると、データベース API を操作するためのイディオムがいくつ もあることに気づくはずです。 Django はこうしたイディオムをショートカット関 数として定義し、ビュー内の処理をすっきりと書けるようにしています。ショート カット関数は django.shortcuts モジュールに収められています。

get_object_or_404()

よく使われるイディオムの一つは、 get() を呼び出し、オブジェクトが存在し ないときには Http404 を送出するというものです。 get_object_or_404() はこの処理を関数にしたものです。 get_object_or_404() は Django モデルを 第一引数に取り、さらに任意のキーワード引数を取れます。キーワード引数はモデ ルのデフォルトマネジャの get() 関数に渡されます。オブジェクトが存在しな ければ Http404 を送出します:

# 主キーが 3 のエントリを取得する
e = get_object_or_404(Entry, pk=3)

このショートカット関数をモデルに渡す場合、背後で get() クエリを受けるの はデフォルトのマネジャです。デフォルト以外のマネジャを使いたい場合や、モデ ルにリレーションを張っているオブジェクトのリストを得たい場合には、以下の例 のように get_object_or_404() にマネジャオブジェクトを直接指定してくださ い:

# Blog モデルのインスタンス ``e`` に関連づけられている、名前が 'Fred'
# の Author インスタンスを取得する
a = get_object_or_404(e.authors, name='Fred')

# カスタムマネジャ 'recent_entries' を使って、主キーが 3 のエントリを
# 検索する
e = get_object_or_404(Entry.recent_entries, pk=3)

開発版の Django で新たに追加された機能です: カスタムマネジャにカスタム メソッドを追加して使いたい場合は、 get_object_or_404() にクエリセット を渡します:

# カスタムマネジャの 'published' メソッドが返すクエリセットを使って
# 主キーの値が 5 のオブジェクトを検索する
e = get_object_or_404(Entry.objects.published(), pk=5)

get_list_or_404()

get_list_or_404 の動作は get_object_or_404() とほとんど同じですが、 get() の代わりに filter() を使い、リストが空の場合に Http404 を 送出します。

生 SQL へのフォールバック

Django のデータベースマッパで扱うには複雑すぎる SQL 文を書かねばならないよ うな場合には、生の SQL 文実行モードを使えます。

生 raw-SQL 文実行モードの使い方としてお勧めなのは、そのようなクエリ文を実行 するモデルのカスタムメソッドやカスタムマネジャのメソッドを実装するというも のです。 Django はモデルレイヤでデータベースクエリを記述するように 要求してはいません が、このアプローチをとることで、データアクセスのための ロジックを一箇所にまとめられるので、コード組織化の観点からスマートになりま す。詳しい説明は カスタム SQL 文の実行 を参照してください。

最後に、 Django のデータベースレイヤは単にデータベースへの一つのインタフェー スに過ぎないということに注意しておきましょう。データベースには他のツールや プログラム言語、データベースフレームワークを介してアクセスできます。データ ベースについて Django 固有の何かがあるわけではないのです。