QuerySet
API リファレンス¶
このドキュメントでは、QuerySet
API の詳細を説明しています。モデル と データベースクエリ ガイドにある説明を前提としていますので、このドキュメントを読む前にこの 2 つを読んでおいた方がよいでしょう。
このリファレンスでは、 データベースクエリガイド で提供された Blogモデルの例 を使用します。
QuerySet
が評価されるタイミング¶
内部的には、 QuerySet
は実際にデータベースにアクセスすることなく、構築、フィルタリング、スライス、受け渡しを行うことができます。クエリセットを評価するための操作が行われない限り、実際のデータベースへのアクセスは発生しません。
あなたは次のような方法で QuerySet
を評価することができます:
イテレーション。
QuerySet
はイテラブルで、初めてイテレートした時にデータベースのクエリを実行します。たとえば、これはデータベースにある全エントリのheadline属性を出力するプログラムです:for e in Entry.objects.all(): print(e.headline)
メモ: 1つ以上の結果が存在するかどうかを判定したいだけなら、これは使わないでください。
exists()
を使った方が効率的です。非同期イテレーション.
QuerySet
はasync for
を使ってイテレートすることもできます:async for e in Entry.objects.all(): results.append(e)
クエリセットの同期的・非同期的イテレータは、同じキャッシュを共有します。
スライス。 QuerySet の要素数を制限する で説明されているとおり、
QuerySet
はPythonのリストスライスを用いてスライスできます。未評価のQuerySet
をスライスすると、通常は新たな未評価のQuerySet
が返されます。しかし、スライスの "step" パラメータを使用した場合、Djangoはデータベースクエリを実行し、リストを返します。評価されたQuerySet
をスライスした場合も同様にリストが返されます。未評価の
QuerySet
をスライスして別の未評価のQuerySet
が返されても、それをさらに変更すること(たとえば、さらにフィルタを追加したり、順序を変更したりすること)は許されていないことに気を付けてください。これは、その操作がSQLに正しく変換されず、明確な意味を持たないためです。Pickle 化/キャッシュ化。 詳細については、後述の pickling QuerySets を参照してください。結果がデータベースから読み出されることが、このセクションの目的として重要なことです。
repr()。
QuerySet
はrepr()
が呼び出された時点で評価されます。これはPythonの対話型インタプリタでの利便性を図るためで、APIを対話的に使用する際にクエリの結果をすぐに確認できます。len()。
QuerySet
はlen()
を呼び出した時点で評価されます。想像される通り、この操作は結果のリストの長さを返します。メモ: セット内のレコード数を決定したいだけであれば(そして実際のオブジェクトが必要ないのであれば)、SQLの
SELECT COUNT(*)
を使ってデータベースレベルでハンドルする方がより効率的です。Djangoはまさにこの理由からcount()
メソッドを提供しています。list()。
list()
を呼び出すことで、QuerySet
の評価を強制します。たとえば:entry_list = list(Entry.objects.all())
bool()。
bool()
,or
,and
またはif
文を使用してブール値としてQuerySet
をテストすると、クエリが実行されます。QuerySet
も少なくとも1つ以上の結果が含まれればTrue
となり、そうでなければFalse
になります。例えば:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
注意: もしクエリの結果が少なくとも1つ存在するかどうかを確認したいだけであれば(そして実際のオブジェクトを必要としないのであれば)、
exists()
を使うべきです。
QuerySet
の Pickle 化¶
QuerySet
を pickle
化するとき、pickle化の前にすべての結果がメモリにロードされるように強制されます。キャッシュされたクエリセットがリロードされた時、結果がすでに存在し、使用できる状態になっていることが望ましいからです(データベースからの読み込みには時間がかかるので、キャッシュとしての目的を達成できません)。つまり、 QuerySet
のpickle化を解除すると、解除した時点でデータベースにある結果ではなく、pickle化した時点での結果が出力されることになります。
もし、後でデータベースから QuerySet
を再生成するために必要な情報だけを取り出したい場合は、 QuerySet
の query
を属性を取り出してください。そうすることで、以下のようなコードで本来の QuerySet
(結果を読み込む前の状態)を再現できます:
>>> import pickle
>>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query # Restore the original 'query'.
query
属性は不透明なオブジェクトです。これは内側でのクエリ構築を表すもので、公開APIの一部ではありません。しかし、ここで説明しているように、この属性の内容のpickle化・pickle化の解除は安全に行うことができます(完全にサポートもされています)。
QuerySet.values_list()
における制限
pickle化された query
属性を使って QuerySet.values_list()
を再生成すると、返り値は QuerySet.values()
に置き換えられます:
>>> import pickle
>>> qs = Blog.objects.values_list("id", "name")
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
QuerySet
API¶
これが QuerySet
の正式な宣言です:
-
class
QuerySet
(model=None, query=None, using=None, hints=None)¶ 通常、
QuerySet
を操作する際には フィルタの連結 を使用します。これを実現するために、ほとんどのQuerySet
のメソッドは新たなクエリセットを返します。これらのメソッドについては、このセクションで後ほど詳しく説明します。QuerySet
クラスは、イントロスペクションのために以下のパブリックな属性を持っています:-
ordered
¶ QuerySet
がorder_by()
やモデルのデフォルトの順序指定によって並び替えられた場合にTrue
となります。それ以外のときはFalse
になります。
-
db
¶ このクエリが実行されるデータベースを示します。
注釈
QuerySet
のquery
パラメータは、特殊なクエリのサブクラスが内部のクエリ状態を再構築できるようにするために存在します。このパラメータの値はクエリの状態の不透明な表現であり、パブリックAPIの一部ではありません。-
新しい QuerySet
s を返すメソッド¶
QuerySet
が返す結果の種類や、SQLクエリの実行方法を変更するための、さまざまな QuerySet
の改良メソッドをDjangoは提供します。
注釈
これらのメソッドはデータベースクエリを実行しないので、非同期コードで実行しても 安全 であり、非同期処理専用のメソッドは存在しません。
filter()
¶
-
filter
(*args, **kwargs)¶
与えられたルックアップパラメータにマッチする新しい QuerySet
を返します。
ルックアップパラメータ (**kwargs
) は以下の Field lookups で説明されているフォーマットに従わなければなりません。複数のパラメータは、元となるSQLステートメントでは AND
によって結合されます。
より複雑なクエリを実行したい場合(たとえば OR
ステートメントを含むクエリ)は、 Q オブジェクト
(*args
) を使用してください。
exclude()
¶
-
exclude
(*args, **kwargs)¶
与えられたルックアップパラメータにマッチ しない 新しい QuerySet
を返します。
ルックアップパラメータ (**kwargs
) は下記の Field lookups で説明されているフォーマットに従わなければなりません。複数のパラメータは、元となる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'
2つ目の例の方が、制約がより強いことに留意してください。
より複雑なクエリを実行したい場合(たとえば OR
ステートメントを含むクエリ)は、 Q オブジェクト
(*args
) を使用してください。
annotate()
¶
-
annotate
(*args, **kwargs)¶
指定された クエリ式 のリストで QuerySet
の各オブジェクトにアノテーションを付けます。式は単純な値、モデル(または関連する任意のモデル)上のフィールドへの参照、または QuerySet
のオブジェクトのリレーション先オブジェクトに対して計算された集計式(平均、合計など)を指定できます。
annotate()
の引数は、それぞれが返り値となる QuerySet
内の各オブジェクトに追加される集計情報となります。
Djangoが提供する集計関数については、下記の Aggregation Functions で説明されています。
キーワード引数を用いて集計情報を定義した場合、キーワードが集計情報のエイリアスとして用いられます。位置引数を用いた場合、使用した集計関数と集計されるモデルフィールドの名前に基づいてエイリアスが生成されます。単一のフィールドを参照する集計式であれば位置引数を利用できます。それ以外のすべての集計式は、キーワード引数を用いなくてはなりません。
たとえば、ブログのリストを操作しているときに、ブログごとのエントリー数を決定したいとします:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Blog
モデル自体は entry__count
属性を定義しませんが、集計式を指定したキーワード引数を用いることで、集計情報の名前を制御できます:
>>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
集計処理についての深い議論については、 アグリゲーションについてのトピックガイド を確認してください。
alias()
¶
-
alias
(*args, **kwargs)¶
annotate()
と同じですが、 QuerySet
にオブジェクトをアノテーションするかわりに、後で他の QuerySet
メソッドで再利用できるように式を保存します。これは式の結果自体は必要ないが、フィルタリングやソート、あるいは複雑な式の一部として利用する場合に便利です。未使用の値を選択しないことで、データベースで冗長な処理を行わずに済み、結果的にパフォーマンスを向上させることができます。
例えば、5エントリ以上のブログを探したいが、エントリ数自体に興味がない場合は、以下のようにできます:
>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)
alias()
は annotate()
, exclude()
, filter()
, order_by()
, update()
と組み合わせて使用できます。エイリアス式をその他のメソッド(aggregate()
など)と組み合わせるためには、アノテーションを用いる必要があります
Blog.objects.alias(entries=Count("entry")).annotate(
entries=F("entries"),
).aggregate(Sum("entries"))
filter()
と order_by()
は式を直接受け取ることができますが、式の構築と評価は同じ場所では行われないことが多いです(例えば、 QuerySet
メソッドは式を作成し、後からビューを表示するときに使用されるため)。 alias()
は、複数のメソッドやモジュールにまたがる複雑な式を段階的に構築することができ、式の部分をエイリアスで参照し、最終結果に対してのみ annotate()
を使用する、といった使い方ができます。
order_by()
¶
-
order_by
(*fields)¶
デフォルトでは、 QuerySet
の返り値はモデルの Meta
内の ordering
オプションで指定されたタプルに基づいて並び替えられます。 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('?')
クエリは、使用するデータベースバックエンドによっては高負荷で遅くなる可能性があります。
異なるモデルのフィールドで並び替えたい場合、モデル間を横断して参照するクエリを発行するときと同じ構文を使用します。すなわち、フィールド名の後にダブルアンダースコア(__
)を続けて、その後に新たなモデルのフィールド名を続けます。そして、それを結合したいモデルの数だけ繰り返します。例えば:
Entry.objects.order_by("blog__name", "headline")
異なるモデルを参照するフィールドで並び替えるとき、Djangoは参照先のモデルのデフォルトの順序を用いますが、 Meta.ordering
が設定されていなければ参照先のモデルのプライマリーキーで並び替えます。たとえば、 Blog
モデルにはデフォルトで設定された順序がないとき:
Entry.objects.order_by("blog")
...は以下と同じです:
Entry.objects.order_by("blog__id")
Blog
が ordering = ['name']
を保持している場合、最初のクエリセットは以下と同じになります:
Entry.objects.order_by("blog__name")
asc()
か desc()
を式の中で呼び出すことで、 クエリ式 を使うこともできます:
Entry.objects.order_by(Coalesce("summary", "headline").desc())
asc()
と desc()
は、null値をどのようにソートするかを制御する引数 (nulls_first
と nulls_last
)をとります。
モデル参照フィールドによる並び替えと同時に distinct()
を使用する際は注意してください。参照先のモデルの順序によって、期待される結果がどのように変化するかについては、 distinct()
の注記を確認してください。
注釈
複数の値をとりうるフィールドを指定し、結果を並び替えることは許されています(たとえば、 ManyToManyField
フィールド、もしくは ForeignKey
フィールドの逆参照など)。
このケースを考えます:
class Event(Model):
parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
related_name="children",
)
date = models.DateField()
Event.objects.order_by("children__date")
ここで、それぞれの Event
に対して、複数の並べ替えデータが存在する可能性があります; 複数の children
を伴う Event
は、order_by()
が作る新たな QuerySet
においてそれぞれ複数回返されることになります。言い換えれば、 QuerySet
で order_by()
を使うことで、もともと作業していたよりも多くの項目を返してしまう可能性があります。これはおそらく予期されることはなく、有用でもないでしょう。
従って、複数の値をとりうるフィールドを結果の並び替えに用いる際は気を付けてください。 もし仮に 並び替える項目ごとに1つのデータしか存在しないのであれば、この方法でも問題はないでしょう。そうでなければ、結果が期待通りになることを確認してください。
大文字と小文字を区別して並べ替えるかどうかを指定することはできません。Djangoは使用するデータベースバックエンドが通常このCase-sensitiveをどのように扱うかに従って結果を並び替えます。
Lower
によって小文字に変換したフィールドで並び替えることで、一貫したルールでの並び替えを実現できます:
Entry.objects.order_by(Lower("headline").desc())
クエリに対し、デフォルトの順序付けも含めて並び替えを適用したくない場合、パラメータを指定せずに order_by()
を呼び出してください。
クエリに並び替えが適用されたかどうかは、 QuerySet.ordered
属性を確認することで知ることができます。 QuerySet
がなんらかの方法で並び替えられれば、この属性の値は True
となります。
order_by()
の呼び出しごとに、過去の並び替えは解除されます。たとえば、以下のクエリでは並び替えに pub_date
が使われ、 headline
は使われません:
Entry.objects.order_by("headline").order_by("pub_date")
警告
ソートには計算コストがかかります。ソート条件に追加した各フィールドに、データベースへのコストが発生します。追加する各外部キーには、暗黙的にすべてのデフォルトのソート条件が含まれます。
クエリでソートが指定されていない場合、データベースから返される結果の順序は指定されません。特定の順序が保証されるのは、結果内の各オブジェクトを一意に識別するフィールドの組み合わせでソートした場合だけです。例えば、 name
フィールドが一意でない場合、そのフィールドでソートしても、同じ名前のオブジェクトが常に同じ順序で表示されるとは限りません。
reverse()
¶
-
reverse
()¶
reverse()
メソッドを使用すると、クエリセットの要素を返す順序を逆にすることができます。再度 reverse()
を呼び出すと、順序が元に戻ります。
クエリセットの「最後の」5つの項目を取り出すには、次のようにします:
my_queryset.reverse()[:5]
この処理がPythonでシーケンスの最後からスライスするのとは全く違うことに注意してください。上記の例では、まず最後の項目が返され、次に最後から5番目の項目が返されます。Python のシーケンスに対して seq[-5:]
を参照すると、最後の 5 番目の項目が最初に表示されるはずです。そのようなアクセスモード (末尾からのスライス) は、SQL で効率的に行うことができないため、Django ではサポートされていません。
また、通常 reverse()
は、順序が定義されている QuerySet
に対してしか呼び出せないことに注意してください(例えば、デフォルトの順序を定義しているモデルに対するクエリや、 order_by()
を使用する場合など)。 QuerySet
に順序が定義されていなかったら、 reverse()
を呼び出しても何の効果もありません(順序は reverse()
を呼び出す前から未定義であり、その後も未定義のままです)。
distinct()
¶
-
distinct
(*fields)¶
SQL クエリで SELECT DISTINCT
を使用した新しい QuerySet
を返します。これにより、クエリ結果から重複した行を取り除くことができます。
デフォルトでは、 QuerySet
は重複した行を削除しません。なぜなら、 Blog.objects.all()
のような単純なクエリでは、結果の行が重複する可能性はないからです。しかし、クエリが複数のテーブルにまたがっている場合、 QuerySet
が評価されたときに重複した結果を得る可能性があります。このような場合は distinct()
を使用します。
注釈
order_by()
の呼び出しで使用されるフィールドはすべて、SQL の SELECT
列に含まれます。これは distinct()
と組み合わせて使用すると、時に予期せぬ結果をもたらすことがあります。リレーション先モデルのフィールドでソートした場合、それらのフィールドが SELECT
の対象に追加され、重複した行が重複していないように出力されるかもしれません。余分なカラムは返される結果には現れないので (カラムは順序付けをサポートするためだけに存在するため)、重複した結果が返されているように見えることがあります。
同様に、 values()
クエリを使用して選択するカラムを制限した場合、 order_by()
(またはデフォルトのモデルの順序付け)で使用したカラムが残存し、結果の一意性に影響する可能性があります。
この問題の解決策は、 distinct()
を使用する場合、リレーション先のモデルによるソートに注意することです。同様に、 distinct()
と values()
を一緒に使う場合、 values()
の呼び出しに含まれないフィールドによるソートに注意する必要があります。
PostgreSQL のみ、位置引数 (*fields
) を渡して、 DISTINCT
を適用するフィールドの名前を指定できます。これは SELECT DISTINCT ON
というSQLクエリに相当します。通常の distinct()
呼び出しでは、データベースはどの行が区別されるかを判断する際に、各行の each フィールドを比較しますが、フィールド名を指定した distinct()
の呼び出しでは、データベースは指定されたフィールド名のみを比較できます。
注釈
フィールド名を指定する場合、QuerySet
に order_by()
を指定する必要があり、 order_by()
のフィールドは distinct()
のフィールドと同じ順序で始まる必要があります。
例えば、SELECT DISTINCT ON (a)
とすると、列 a
の各値の最初の行が得られます。もし順序を指定しなければ、任意の行を得ることができます。
例 (2つ目以降のコードは、PostgreSQL上でのみ動作します):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]
>>> Entry.objects.order_by("blog").distinct("blog")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]
>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]
注釈
order_by()
はデフォルトで定義されているリレーション先モデルのソートを使用することに注意してください。 ORDER BY
句の先頭にある DISTINCT ON
式が一致するように、明示的に _id
やフィールド参照によるソートをする必要があるかもしれません。例えば、 Blog
モデルが name
による ordering
を定義していた場合、:
Entry.objects.order_by("blog").distinct("blog")
このコードは、クエリが blog__name
によってソートされるため DISTINCT ON
式と食い違ってしまい、正しい結果を得られないでしょう。2つの式が一致するように、リレーションの _id
フィールド(この場合は blog_id
)またはフィールド参照( blog__pk
)によって明示的にソートする必要があります。
values()
¶
-
values
(*fields, **expressions)¶
イテラブルオブジェクトとして使用するとき、モデルインスタンスではなく辞書を返す QuerySet
を返します。
これらの辞書はそれぞれオブジェクトを表し、キーはモデルオブジェクトの属性名に対応しています。
この例では、values()
によって得られる辞書と通常のモデルのオブジェクトを比較しています:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
values()
メソッドはオプションの位置引数 *fields
を取り、 SELECT
で絞り込むフィールド名を指定します。フィールドを指定した場合、それぞれの辞書は指定したフィールドのキー/値のみを保有します。フィールドを指定しない場合、各辞書は、データベーステーブルのすべてのフィールドのキーと値を保有します。
例:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
values()
メソッドはオプションでキーワード引数 **expressions
を受け取り、 annotate()
に渡すこともできます:
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
ソートには、組み込みのルックアップまたは カスタムルックアップ が使用できます。例えば、次のようになります:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
values()
句内の集計処理は、同じ values()
句内の他の引数の前に適用されます。別の値でグループ化する必要がある場合は、その値を先の values()
句に追加してください。例えば:
>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
いくつかの際どいポイントについて言及しておきます:
もし
foo
というフィールドがForeignKey
である場合、デフォルトのvalues()
はfoo_id
という辞書キーを返します。それが実際の値を格納するモデルの隠し属性名だからです (foo
属性はリレーション先モデルを指します)。value()
を呼び出してフィールド名を渡す場合、foo
とfoo_id
のどちらを渡しても、同じものが返ってきます(辞書のキーは渡したフィールド名と一致します)。例:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values("blog") <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values("blog_id") <QuerySet [{'blog_id': 1}, ...]>
values()
とdistinct()
を一緒に使う場合、呼び出す順番が結果に影響する場合があるので注意してください。 詳細はdistinct()
のノートを参照してください。extra()
呼び出しの後にvalues()
句を使用する場合、extra()
のselect
引数で定義したフィールドは、明示的にvalues()
呼び出しに含めなければなりません。values()
呼び出しの後にextra()
を呼び出しても、後から追加した選択フィールドは返り値に含まれません。values()
の後にonly()
とdefer()
を呼び出すのは意味がなく、TypeError
が発生します。トランスフォームと集計の処理を組み合わせるには、2つの
annotate()
呼び出しを、明示的にまたはvalues()
へのキーワード引数として使用する必要があります。上記の例のように、リレーション先のフィールドタイプにトランスフォームが登録されていれば、最初のannotate()
は省略できます。よって以下の例はすべて等価です:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate( ... entries=Count("entry") ... ) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values( ... "entry__authors__name__lower" ... ).annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
これは、値が欲しい利用可能フィールドが少なく、モデルインスタンスオブジェクトの機能が必要ないことが分かっている場合に便利です。使用する必要のあるフィールドだけを選択する方がより効率的です。
最後に、values()
の後に filter()
や order_by()
などを呼び出すことができますが、これはこの2つの呼び出しが同じであることを意味しています:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
Django を作った人たちは、SQL に影響するメソッドを最初に置き、その後に出力に影響するメソッド (values()
など) を (オプションで) 置くことを好みますが、それは本当に重要ではありません。しかし、そんなことはどうでもいいのです。この機会に、あなたの個性を存分に発揮してください。
リレーション先モデルのフィールドには、 OneToOneField
、 ForeignKey
、 ManyToManyField
属性を使用して逆リレーションで参照することもできます。
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
警告
ManyToManyField
属性と逆リレーションは複数の関連行を持つので、これらを含めると結果のサイズが数倍になることがあります。これは、 values()
クエリに複数のフィールドを含めると特に顕著で、その場合、考えられるすべての組み合わせが返されることになります。
SQLiteにおける JSONField
の特殊な値
SQLiteでは、 JSON_EXTRACT
と JSON_TYPE
は実装されていますが、 BOOLEAN
データ型がないため、 values()
は JSONField
のキーを変換する際に true
, False
, None
の代わりに "true"
, "false"
, "null"
の代わりに True
, False
, None
を返します。
values_list()
¶
-
values_list
(*fields, flat=False, named=False)¶
この関数は values()
と似ていますが、イテレートしたときに辞書の代わりにタプルを返します。それぞれのタプルには、 values_list()
に渡された各フィールドまたは式の値が、渡された順番で含まれます。例えば:
>>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>
フィールドを1つだけ渡す場合は、 flat
パラメータを渡すことができます。これに True
を渡すと、返り値はタプルではなく単一の値になります。この違いは例を見て理解してください。
>>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>
複数のフィールドがある場合に flat
を渡すとエラーになります。
namedtuple()
: として結果を得るには、named=True
を渡します:
>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
名前付きタプルを使用することで、名前付きタプルに変換するためのわずかなパフォーマンスの低下を犠牲にして、クエリの実行結果の可読性を高めることができます。
もし values_list()
に何も値を渡さなければ、モデル内のすべてのフィールドを宣言された順に返します。
よくあるニーズは、特定のモデルインスタンスの特定のフィールドの値を取得することです。これを実現するには、 values_list()
の後に get()
を呼び出します:
>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
values()
と values_list()
はいずれも、モデルインスタンスを作成するオーバーヘッドなしにデータのサブセットを取得するという、特定のユースケースに対する最適化を意図したものです。このメタファーは、多対多の関係やその他の多値の関係(逆引き外部キーの1対多の関係など)を扱うときには、「1行に1オブジェクト」の前提が成り立たないために崩れてしまいます。
例えば、 ManyToManyField
: を通してクエリを実行したときの挙動に注目してみましょう:
>>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
複数のエントリを持つ著者は複数回表示され、エントリのない著者のエントリとして None
と表示されます。
同様に、外部キーを逆引きするクエリでは、著者が設定されていないエントリに対して None
が表示されます。
>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
SQLiteにおける JSONField
の特殊な値
SQLiteでは、 JSON_EXTRACT
と JSON_TYPE
は実装されていますが、 BOOLEAN
データ型がないため、 values_list()
は JSONField
のキーを変換する際に "true"
, "false"
, and "null"
の代わりに True
, False
, None
の文字列を返します。
dates()
¶
-
dates
(field, kind, order='ASC')¶
この QuerySet
は datetime.date
オブジェクトのリストとして評価され、QuerySet
の内容から指定された種類の日付を返します。
field
にはモデルの DateField
の名前を指定します。 kind
には "year"
, "month"
, "week"
, "day"
のいずれかを指定します。結果のリストに含まれる datetime.date
オブジェクトは、指定された type
に "切り捨て" られます。
"year"
は、そのフィールドのすべての年の値のリストを重複なしで返します。"month"
はそのフィールドの年/月の値のリストを重複なしで返します。"week"
はそのフィールドの年/週の値のリストを重複なしで返します。すべての date は月曜日になります。"day"
はそのフィールドの年/月/日の値のリストを重複なしで返します。
order
のデフォルトは 'ASC'
で、 'ASC'
または 'DESC'
のいずれかを指定します。これは結果のソート方法を指定します。
例:
>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
datetimes()
¶
-
datetimes
(field_name, kind, order='ASC', tzinfo=None)¶
これは、QuerySet
内の指定した種類の有効な日付を表す datetime.datetime
オブジェクトのリストとして評価される QuerySet
を返します。
field_name
にはモデルの DateTimeField
の名前を指定します。
kind
には "year"
, "month"
, "week"
, "day"
, "hour"
, "minute"
, "second"
のいずれかを指定します。結果のリストに含まれる datetime.datetime
オブジェクトは、指定された type
に " 切り捨て" られます。
order
のデフォルトは 'ASC'
で、 'ASC'
または 'DESC'
のいずれかを指定します。これは結果のソート方法を指定します。
tzinfo
は、日時が切り捨てられる前に変換されるタイムゾーンを定義します。実際、与えられた日時は使用されるタイムゾーンによって異なる表現を持ちます。このパラメータは datetime.tzinfo
オブジェクトでなければなりません。None
の場合、Djangoは カレントタイムゾーン を使用します。USE_TZ
が False
の場合には効果がありません。
注釈
この関数はデータベース内で直接タイムゾーンの変換を行います。そのため、データベースは tzinfo.tzname(None)
の値を解釈できなければなりません。これは以下の要件になります:
- SQLite: 要件はありません。変換はPythonで行われます。
- PostgreSQL: 要件はありません( Time Zones を参照)。
- Oracle: 要件はありません( Choosing a Time Zone File を参照)。
- MySQL: mysql_tzinfo_to_sql でタイムゾーンテーブルをロードすること。
none()
¶
-
none
()¶
none()
を呼び出すと、オブジェクトを返さないクエリセットが作成され、結果にアクセスする際にクエリが実行されることはありません。 qs.none()
のクエリセットは EmptyQuerySet
のインスタンスです。
例:
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
all()
¶
-
all
()¶
現在の QuerySet
(または QuerySet
サブクラス)の コピー を返します。これは、モデルマネージャまたは QuerySet
のどちらかを渡して、その結果に対してさらにフィルタリングを行いたいときに便利です。いずれかのオブジェクトに対して all()
を呼び出すと、動作する QuerySet
が必ず作成されます。
QuerySet
が 評価される とき、通常その結果はキャッシュされます。もし QuerySet
が評価された後にデータベースのデータが更新された場合、以前に評価された QuerySet
に対して all()
を呼び出すことで、同じクエリの最新の結果を取得できます。
union()
¶
-
union
(*other_qs, all=False)¶
SQLの UNION
コマンドを使用して、2つ以上の QuerySet
の結果を結合します。例えば:
>>> qs1.union(qs2, qs3)
UNION
演算子は、デフォルトでは明確な値のみを選択します。重複した値を取得するには、 all=True
引数を使用します。
union()
, intersection()
, difference()
は、引数が他のモデルの QuerySet
であっても、最初の QuerySet
の型のモデルインスタンスを返します。すべての QuerySet
で SELECT
リストが同じであれば、異なるモデルを渡すことができます(少なくとも型と、型の順番が同じであれば名前は関係ありません)。 このような場合、結果の QuerySet
に適用される QuerySet
メソッドでは、最初の QuerySet
のカラム名を使用する必要があります。たとえば、次のようになります:
>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")
結果として得られる QuerySet
では、LIMIT
、OFFSET
、COUNT(*)
、ORDER BY
、およびカラムの指定(すなわち、スライス、 count()
、 exists()
、 order_by()
、 values()
/ values_list()
)のみが許可されます。さらに、データベースによっては、組み合わせたクエリで許可される操作に制限があります。例えば、ほとんどのデータベースでは組み合わせたクエリで「LIMIT」や「OFFSET」は許可されていません。
intersection()
¶
-
intersection
(*other_qs)¶
SQL の INTERSECT
演算子を使用して、2つ以上の QuerySet
の全てに含まれる共有要素を返します。例:
>>> qs1.intersection(qs2, qs3)
制限については union()
を参照してください。
difference()
¶
-
difference
(*other_qs)¶
SQL の EXCEPT
演算子を使用して、 QuerySet
には存在するが、他の QuerySet
には存在しない要素のみを保持します。例:
>>> qs1.difference(qs2, qs3)
制限については union()
を参照してください。
extra()
¶
-
extra
(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)¶
Django のクエリ構文だけでは、複雑な WHERE
節を簡単に表現できないことがあります。このようなエッジケースのために、 Django は extra()
QuerySet
修飾子、つまり QuerySet
が生成する SQL に特定の句を注入するフックを提供します。
このやり方は最後の手段として使ってください。
これは古い API で、将来的には非推奨とする予定です。他の QuerySet メソッドでクエリを表現できない場合にのみ使用してください。もしあなたがこのメソッドを必要とするのであれば、私たちが QuerySet APIを拡張して extra()
を削除できるように、 QuerySet.extra キーワード とあなたの使用例を添えて チケットを提出 してください (ただしその前に既存のチケットのリストを確認してください)。このメソッドの改善やバグの修正はもう行っていません。
例えば、 extra()
を使った下記のコードは:
>>> qs.extra(
... select={"val": "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
下記と等価です:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
RawSQL
を使う主な利点は、必要に応じて output_field
を指定できることです。主な欠点は、生の SQL でクエリセットのテーブルエイリアスを参照すると、Django がそのエイリアスを変更する可能性があることです (たとえば、クエリセットが別のクエリのサブクエリとして使われる場合など)。
警告
extra()
を使うときは常に細心の注意を払ってください。SQL インジェクション攻撃から守るために、使うときは常に params
を使用して、ユーザが制御できるパラメータをエスケープする必要があります。
また、SQL文字列のプレースホルダを引用符で囲んではいけません。この例では %s
を引用符で囲んでいるため、SQLインジェクションに対して脆弱です:
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Django が SQL インジェクションを防ぐ 仕組みの説明があります。
定義上、これらの extra ルックアップは異なるデータベースエンジンに移植できない可能性があり(明示的にSQLコードを記述しているため)、DRY原則に違反するため、可能であれば避けるべきです。
params
、select
、where
、tables
のうち、少なくとも1つを指定します。どの引数も必須ではありませんが、少なくとも1つは指定する必要があります。
select
select
引数を使用すると、SELECT
句に追加のフィールドを配置できます。属性名を SQL 句にマッピングした辞書を使用して、その属性を計算するために使用します。実装例:
Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
その結果、各
Entry
オブジェクトには、追加の属性であるis_recent
が付与されます。これは、エントリーのpub_date
が2006年1月1日よりも後の日付であるかどうかを表す真偽値です。Django は指定された SQL スニペットを
SELECT
文に直接挿入するので、上の例の SQL は次のようになります:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
次の例はもっと高度です。サブクエリを使って、各結果の
Blog
オブジェクトに、関連するEntry
オブジェクトの整数カウントである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) AS entry_count FROM blog_blog;
ほとんどのデータベースエンジンで、サブクエリを囲む必要のある括弧は、Django の "select" 句では不要です。また、一部のデータベースバックエンド(一部のMySQLバージョンなど)はサブクエリをサポートしていないことに注意してください。
まれに、
extra(select=...)
でSQLフラグメントにパラメータを渡したい場合があります。その場合は、select_params
パラメータを使用してください。これは、次のように動作します:
Blog.objects.extra( select={"a": "%s", "b": "%s"}, select_params=("one", "two"), )
select 文内で文字列
%s
をそのまま使いたい場合は、%%s
というシーケンスを使用してください。where
/tables
SQLの明示的な
WHERE
句を定義できます。たとえば、明示的でない結合を実行するためにwhere
を使用できます。また、SQLのFROM
句に手動でテーブルを追加できます。これにはtables
を使用します。where
とtables
は、どちらも文字列のリストを取ります。全てのwhere
パラメーターは、他の検索条件と "AND" 演算されます。実装例:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
...これは大まかに次の SQL に翻訳されます:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
すでにクエリで使われているテーブルを指定する場合、
tables
パラメータを使うときには注意してください。テーブルtables
パラメータを使ってテーブルを追加すると、 Django はそのテーブルが既に含まれている場合、そのテーブルをもう一回追加したいと仮定します。この場合、テーブル名にエイリアスが付けられるので、問題が生じます。テーブルが SQL 文の中で複数回出現する場合、データベースが区別できるように、2 回目以降の出現にはエイリアスを使う必要があります。追加のwhere
パラメータで追加したテーブルを参照している場合、これはエラーの原因になります。通常は、クエリに既に表示されていない追加のテーブルのみを追加します。しかし、上記の場合が発生した場合は、いくつかの解決策があります。まず、追加のテーブルを含めずに、すでにクエリにあるテーブルを使用できるかどうかを確認してください。それが不可能な場合は、
extra()
メソッドをクエリセットの構築の最初に配置して、そのテーブルが最初に使用されるようにします。最後に、すべてが失敗した場合は、生成されたクエリを確認し、where
句への追加をエイリアスの利用に書き直します。エイリアスは、同じ方法でクエリセットを構築するたびに同じであるため、エイリアス名は変わらないことを信頼できます。order_by
extra()
で追加した新しいフィールドやテーブルを使用してクエリセットを並べ替える必要がある場合は、extra()
のorder_by
パラメータを使用し、文字列のシーケンスを渡します。 これらの文字列は、通常の querysets の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 であるすべてのアイテムが結果セットの先頭に並べ替えられます (降順ではTrue
がFalse
よりも先に並びます)。ちなみに、これは
extra()
を複数回呼び出しても期待通りに動作する(つまり、毎回新しい制約を追加する)ことを示しています。params
上記の
where
パラメータは、標準のPythonデータベース文字列プレースホルダー、'%s'
を使用して、データベースエンジンが自動的に引用符で囲むべきパラメータを示すことができます。params
引数は、代入される追加のパラメータのリストです。実装例:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
常に
params
を使用し、値を直接where
に埋め込まないでください。なぜならparams
を使用することで、値が特定のバックエンドに応じて正しく引用符で囲まれることが保証されるからです。例えば、引用符は正しくエスケープされます。悪い例:
Entry.objects.extra(where=["headline='Lennon'"])
良い例:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
警告
もしあなたが MySQL でクエリを処理する場合は、複数の型を扱う際に MySQL の暗黙的な型変換が予期しない結果をもたらす場合がある事に注意してください。もし文字列型で定義したカラムに対し、数値型の値で問い合わせた場合、MySQL は比較処理を行う前にテーブル上の全ての値の型を数値型に変換します。例えば 'abc'
、 'def'
といった値が含まれているテーブルに対して WHERE mycolumn=0
という条件での問い合わせを行うと、両方の行がマッチします。これを防ぐため、クエリの値を利用する前に適切な型キャストを行ってください。
defer()
¶
-
defer
(*fields)¶
複雑なデータモデリングの場面では、モデルにはたくさんのフィールドが含まれるかもしれません。その中には、大量のデータを含むフィールド (たとえばテキストフィールド) や、Python オブジェクトに変換するために高コストな処理を必要とするフィールドがあるかもしれません。QuerySet の結果を、最初にデータを取得するときにはまだそのフィールドが必要かどうかわからないような状況で使う場合、まだデータベースからは読み込まないように Django に指示できます。
読み込ませたくないフィールドの名前を defer()
に渡すことで、それを実現できます:
Entry.objects.defer("headline", "body")
Defer(遅延読み込み)されたフィールドを持つ QuerySet はモデルインスタンスを返します。それぞれの遅延読み込みフィールドは、そのフィールドにアクセスしたときにデータベースから取得されます (すべての遅延読み込みフィールドを一度に取得するのではなく、1つずつ取得します)。
注釈
遅延読み込みに指定されたフィールドは非同期コードからはこのように遅延ロードすることはできません。代わりに SynchronousOnlyOperation
例外が発生します。もし非同期コードを書いているのであれば、defer()
されたフィールドにアクセスしようとしてはいけません。
defer()
を複数回呼び出すこともできます。それぞれの呼び出しは新しいフィールドを遅延読み込みリストに追加します:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
フィールドが遅延読み込みリストに追加される順番は重要ではありません。すでに遅延読み込みに指定されているフィールド名で defer()
を呼び出しても意味はありません(フィールドは遅延読み込みに指定されたままです)。
標準的な2重アンダースコア記法を用いてリレーション先のフィールドを区切ることで、(リレーション先のモデルが select_related()
によって読み込まれる場合) リレーション先のモデルのフィールドの読み込みを遅延させることもできます:
Blog.objects.select_related().defer("entry__headline", "entry__body")
遅延読み込みフィールドの指定を消去したい場合は、 defer()
のパラメータとして None
を渡します:
# Load all fields immediately.
my_queryset.defer(None)
モデル内のいくつかのフィールドは、指定しても遅延読み込みされません。主キーの読み込みは決して遅延できません。リレーション先のモデルを取得するために select_related()
を使っている場合、最初のモデルからリレーション先のモデルに接続するフィールドの読み込みを遅延すべきではありません。
同様に、 defer()
(またはそれに対応する only()
) を集計関数の引数を含めて (例えば annotate()
の結果を使って) 呼び出しても意味はありません。集計された値は常に結果の QuerySet に取り込まれます。
注釈
defer()
メソッド(およびその同類である only()
、以下同様)は高度なユースケースのためのものです。クエリを詳細に分析し、どのような情報が必要かを 正確に 理解し、必要なフィールドを返すこととモデルの全フィールドを返すことの差が大きいと判断した場合の最適化を提供するものです。
高度なユースケースだと思う場合でも、 defer()
を使用するのは、 QuerySetのロード時に、余分なフィールドが必要かどうかを判断 できない場合だけ にしてください。データの特定のサブセットを頻繁に読み込んで使うなら、モデルを正規化し、ロードしないデータを別のモデル(とデータベーステーブル)に置くのが最善の選択です。もしカラムを一つのテーブル内に どうしても保持する必要がある 場合は、 Meta.managed = False
(managed 属性
のドキュメントを参照) に設定されたモデルを作成し、通常必要なフィールドのみを含めます。これは、通常 defer()
を呼び出す場合に使用します。これにより、コードは読み手に対してより明示的になり、わずかに速くなり、Pythonプロセスで消費するメモリも少し減ります。
たとえば、これらのモデルはどちらも同じデータベーステーブルを使用しています:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = "app_largetable"
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = "app_largetable"
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer("f2")
非マネージドモデルと多くのフィールドを重複させる必要がある場合、共有フィールドを持つ抽象モデルを作成し、非マネージドモデルとマネージドモデルに抽象モデルを継承させるのが最善でしょう。
only()
¶
-
only
(*fields)¶
only()
メソッドは本質的に defer()
の逆です。このメソッドに渡されたフィールドのうち、既に遅延読み込みフィールドに指定されていないものだけが、 QuerySet が評価されたときに直ちにロードされます。
ほとんどのフィールドが遅延読み込みされる必要があるようなモデルの場合、only()
を使って補完的なフィールドセットを指定すると、よりシンプルなコードになります。
name
, age
, biography
という3つのフィールドを持つモデルがあるとします。次の2つのQuerySetは、どのフィールドが遅延読み込みされるかという点では同じです:
Person.objects.defer("age", "biography")
Person.objects.only("name")
only()
を呼び出すと、読み込むフィールドの設定を即座に置き換えます。このメソッドは名前の通り、指定したフィールド だけ を読み込み、残りのフィールドの読み込みを先送りします。その結果、連続して only()
を呼び出すと、最後に指定したフィールドだけが考慮されることになります:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
defer()
は段階的に(遅延読み込みリストにフィールドを追加しながら)動作するので、 only()
と defer()
の呼び出しは組み合わせることができ、ロジカルに動作します:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")
defer()
のドキュメントにある注意事項はすべて only()
にも当てはまります。 only()
は慎重に、そして他のオプションを使い果たした後にだけ使用してください。
only()
を使って select_related()
で要求したフィールドを省略した場合もエラーになります。 一方、引数なしで only()
を呼び出すと、queryset によって取得された全てのフィールド (アノテーションを含む) が返されます。
defer()
と同様に、非同期コードからは、まだ読み込まれていないフィールドにアクセスすることはできません。その場合、SynchronousOnlyOperation
例外が発生します。アクセスする可能性のあるすべてのフィールドが only()
呼び出し内に含まれていることを確認してください。
using()
¶
-
using
(alias)¶
このメソッドは、複数のデータベースを使用している場合に QuerySet
がどのデータベースに対して評価されるかを制御するためのものです。 このメソッドが受け取る唯一の引数は DATABASES
で定義されているデータベースのエイリアスです。
例:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using("backup")
select_for_update()
¶
-
select_for_update
(nowait=False, skip_locked=False, of=(), no_key=False)¶
トランザクションが終了するまで行をロックし、サポートされているデータベース上で SELECT ... FOR UPDATE
SQL 文を生成する QuerySet を返します。
例:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
クエリセットが評価されるとき(この場合、 for entry in entries
)、マッチしたすべてのエントリは、トランザクションブロックが終了するまでロックされます。つまり、他のトランザクションがそれらのエントリを変更したりロックを取得したりするのを防ぐことができます。
通常、他のトランザクションが既に選択行の1つをロックしている場合、ロックが解除されるまでクエリはブロックされます。このような動作が望ましくない場合は、 select_for_update(nowait=True)
を呼び出してください。これにより、呼び出しがノンブロッキングになります。競合するロックが既に他のトランザクションによって取得されている場合は、クエリセットが評価される際に DatabaseError
が発生します。代わりに select_for_update(skip_locked=True)
を使用すれば、ロックされた行を無視することもできます。 nowait
と skip_locked
は互いに排他的であり、両方のオプションを有効にして select_for_update()
を呼び出そうとすると ValueError
が発生します。
デフォルトでは、 select_for_update()
はクエリによって選択された全ての行をロックします。たとえば、クエリセットのモデルの行に加えて、 select_related()
で指定したリレーション先のオブジェクトの行もロックされます。この動作が望ましくない場合は、 select_related()
と同じフィールド構文を使って select_for_update(of=(...))
でロックしたいリレーション先のオブジェクトを指定してください。クエリセットのモデルを参照するには 'self'
という値を使用します。
親モデルを select_for_update(of=(...))
でロックする
複数テーブルの継承 を使用する際に親モデルをロックしたい場合は、 of
引数に親リンクフィールド (デフォルトでは <parent_model_name>_ptr
) を指定する必要があります。たとえば次のようになります:
Restaurant.objects.select_for_update(of=("self", "place_ptr"))
フィールドを指定して select_for_update(of=(...))
を使う
例えば values()
を使ってモデルをロックし、選択されたフィールドを指定したい場合、 of
引数で各モデルから少なくとも1つのフィールドを選択する必要があります。フィールドが選択されていないモデルはロックされません。
PostgreSQLの場合のみ、no_key=True
を渡すことで、ロックがかかっている間、(たとえば外部キーによって)ロックされた行を参照するだけの行を作成できる、より弱いロックを取得できます。PostgreSQLのドキュメントに row-level lock modes についての詳細があります。
null 可能なリレーションでは select_for_update()
は使用できません:
>>> Person.objects.select_related("hometown").select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
この制限を回避するために、nullオブジェクトを気にしない場合は除外できます:
>>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
データベースバックエンドの postgresql
、 oracle
、 mysql
は select_for_update()
をサポートしています。ただし、MariaDB は nowait
引数のみをサポートしており、MariaDB 10.6+ は skip_locked
引数もサポートしています。 no_key
引数は PostgreSQL のみでサポートされています。
nowait=True
、 skip_locked=True
、 no_key=True
、または of
を select_for_update()
に渡すと、MySQL のようなこれらのオプションをサポートしていないデータベースバックエンドでは NotSupportedError
が発生します。これはコードが予期せずブロックされるのを防ぎます。
SELECT ... FOR UPDATE
をサポートしているバックエンドで select_for_update()
をオートコミットモードでクエリセットを評価すると TransactionManagementError
エラーになります。もしこれが許される場合、これはデータを用意に破壊します。たとえばトランザクショ ン外のトランザクションで実行されることを期待するコードを呼び出すことで簡単に破壊が起こります。
SELECT ... FOR UPDATE
をサポートしていないバックエンド (SQLite など) で select_for_update()
を使用しても意味はありません。 SELECT ... FOR UPDATE
はクエリに追加されず、 select_for_update()
がオートコミットモードで使用されてもエラーは発生しません。
警告
自動コミットモードでは select_for_update()
は通常失敗しますが、 TestCase
は自動的に各テストをトランザクションでラップするので、 atomic()
ブロックの外でも TestCase
の中で select_for_update()
を呼び出すと、(おそらく予期せず) TransactionManagementError
を発生させずに通過します。正しく select_for_update()
をテストするには TransactionTestCase
を使うべきです。
一部の式はサポートされていません
PostgreSQL は select_for_update()
を Window
式でサポートしていません。
raw()
¶
-
raw
(raw_query, params=(), translations=None, using=None)¶
素の SQL クエリを受け取って実行し、 django.db.models.query.RawQuerySet
インスタンスを返します。この RawQuerySet
インスタンスは、通常の QuerySet
と同様にイテレートすることで、オブジェクトインスタンスを生成できます。
詳細は 素の SQL 文の実行 を参照してください。
警告
raw()
は常に新しいクエリをトリガーし、以前のフィルタリングを考慮しません。そのため、通常は Manager
から呼び出すか、新しい QuerySet
インスタンスから呼び出す必要があります。
新しい QuerySet
を返す演算子¶
結合したクエリセットは同じモデルを使用しなければなりません。
AND (&
)¶
SQL の AND
演算子を使い、フィルタを連結するのと同じように、2つの QuerySet
を結合します。
以下のコードは同等です:
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1).filter(y=2)
これらは SQL で言う下記と同等です:
SELECT ... WHERE x=1 AND y=2
OR (|
)¶
SQL の OR
演算子を使用して、2つの QuerySet
を結合します。
以下のコードは同等です:
Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))
これらは SQL で言う下記と同等です:
SELECT ... WHERE x=1 OR y=2
|
は可換演算ではないので、(等価ではあるが)異なるクエリが生成される可能性があります。
XOR (^
)¶
SQLの XOR
演算子を使用して、2つの QuerySet
を結合します。XOR
式は、奇数個の条件が真である行にマッチします。
以下のコードは同等です:
Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) ^ Q(y=2))
これらは SQL で言う下記と同等です:
SELECT ... WHERE x=1 XOR y=2
注釈
XOR
は MariaDB と MySQL ではネイティブでサポートされています。 他のデータベースでは、x ^ y ^ .... z
は下記と等価な式に変換されます:(x OR y OR ... OR z) AND 1=MOD( (CASE WHEN x THEN 1 ELSE 0 END) + (CASE WHEN y THEN 1 ELSE 0 END) + ... (CASE WHEN z THEN 1 ELSE 0 END), 2 )
古いバージョンでは、SQL の XOR
演算子をネイティブにサポートしていないデータベースでは、 XOR
はただ1つの演算子でマッチする行だけを返していました。 以前の動作は MySQL、MariaDB、Python の動作と一致していませんでした。
QuerySet
を返さないメソッド¶
以下の QuerySet
メソッドは QuerySet
を評価し、 QuerySet
以外のものを返します。
これらのメソッドはキャッシュを使用しません ( キャッシュと QuerySet を参照してください)。むしろ、呼び出されるたびにデータベースにクエリを行います。
これらのメソッドは QuerySet
を評価するので、ブロッキング呼び出しとなり、そのため主な(同期)バージョンは非同期コードから呼び出すことはできません。このため、それぞれに対応する非同期バージョンがあり、 a
接頭辞が付いています。例えば、 get(…)
の代わりに await aget(…)
が使用できます。
これらのメソッドの挙動には、通常その非同期性以外に違いはありませんが、各メソッドの具体的な違いは、それぞれのメソッドの説明のすぐそばに記載されています。
get()
¶
-
get
(*args, **kwargs)¶
-
aget
(*args, **kwargs)¶
非同期バージョン: aget()
指定されたルックアップパラメータに一致するオブジェクトを返します。これらのパラメータは、 Field lookups で説明されている形式に従うべきです。主キーやユニーク制約のあるフィールドのように、一意性が保証されるルックアップを使うべきです。例えば下記のようにします:
Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))
クエリセットがすでに1行だけを返すことがわかっている場合、引数なしで get()
を使うことでその行のオブジェクトを取得できます。
Entry.objects.filter(pk=1).get()
もし``get()`` がオブジェクトを見つけられなかった場合は、 Model.DoesNotExist
例外が発生します。
Entry.objects.get(id=-999) # raises Entry.DoesNotExist
もし get()
が複数のオブジェクトを見つけた場合は、 Model.MultipleObjectsReturned
例外が発生します。
Entry.objects.get(name="A Duplicated Name") # raises Entry.MultipleObjectsReturned
これらの例外クラスはモデルクラスの属性であり、そのモデルに特有のものです。複数のモデルに対する get()
呼び出しでこのような例外を処理したい場合、一般的な基底クラスを使用できます。たとえば下記のように、 django.core.exceptions.ObjectDoesNotExist
を使って、複数のモデルからの DoesNotExist
例外をできます:
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.")
create()
¶
-
create
(**kwargs)¶
-
acreate
(**kwargs)¶
非同期バージョン: acreate()
1ステップでオブジェクトを作成して保存するための便利なメソッドす。たとえばこのようにします:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
そして、:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
これらは同等です。
別の場所で force_insert パラメータについても説明していますが、それは新しいオブジェクトを常に作成するよう強制するものです。普通はこれを気にする必要はありません。しかし、モデルが手動で指定した主キー値を含み、その値が既にデータベースに存在する場合、 create()
の呼び出しは IntegrityError
で失敗します。これは、主キーは一意である必要があるためです。手動の主キーを使用している場合は、例外処理に備える必要があります。
get_or_create()
¶
-
get_or_create
(defaults=None, **kwargs)¶
-
aget_or_create
(defaults=None, **kwargs)¶
非同期バージョン: aget_or_create()
与えられた kwargs
を持つオブジェクトを検索するための便利なメソッドです (モデルがすべてのフィールドをデフォルトで持っている場合は空でもかまいません)。
(Object, created) のタプルを返します。"Object"は受け取ったものか作られたものです。そして"created"はそのObjectが作られたものかどうかのBooleanです。
これは、リクエストが並列処理されたときに、重複したオブジェクトが生成されるのを防ぐため、また、定型的なコードへのショートカットのためです。たとえば次のような場合、:
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()
ここで、同時リクエストにより、同じパラメータで Person
を保存しようとする試みが複数回行われる可能性があります。この競合状態を回避するために、上記の例は 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
のタプルを返します。
警告
このメソッドはデータベースがキーワード引数の一意性を強制していると仮定してアトミックに動作します (unique
または unique_together
を参照してください)。キーワード引数で使用されるフィールドにユニーク制約がない場合、このメソッドを同時に呼び出すと、同じパラメータを持つ複数の行が挿入される可能性があります。
get_or_create()
と filter()
を連結し、 Q オブジェクト
を使用することで、取得するオブジェクトに対してより複雑な条件を指定できます。たとえば次のコードは、Robert と Bob Marley のどちらかが存在すればそれを取得し、そうでなければ後者(Bob Marley)を作成します:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name="Bob") | Q(first_name="Robert"),
).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})
複数のオブジェクトが見つかった場合、 get_or_create()
は MultipleObjectsReturned
を発生させます。オブジェクトが ** 見つからなかった** 場合、 get_or_create()
は新しいオブジェクトをインスタンス化して保存し、新しいオブジェクトと True
のタプルを返します。新しいオブジェクトはおおよそ以下のアルゴリズムに従って作成されます:
params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
英語では、defaults'
以外のキーワード引数で、2重アンダースコア(これはexact以外のルックアップを意味します)を含まないものから始めることを意味します。次に defaults
の内容を追加し、必要であればキーを上書きして、その結果をモデルクラスのキーワード引数として使用します。もし defaults
に呼び出し可能オブジェクトがあれば、それを評価します。上記のように、これは使用されるアルゴリズムを簡略化したものですが、適切な詳細はすべて含まれています。内部実装では、これよりもさらに多くのエラーチェックが行われ、エッジ条件も処理されます。興味があれば、コードを読んでください。
もし defaults
という名前のフィールドがあり、それを get_or_create()
で正確にルックアップしたい場合は、次のように 'defaults__exact'
を使用します:
Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
get_or_create()
メソッドは create()
と同様のエラー動作をします。オブジェクトを作成する必要があり、そのキーが既にデータベースに存在する場合、 IntegrityError
が発生します。
最後に、Djangoビューで``get_or_create()``を使用する際の注意点について説明します。よほどの理由がない限り、 POST
リクエスト以外では使用しないようにしてください。 GET
リクエストはデータに影響を与えるべきではありません。代わりに、データに副作用がある場合は常に``POST``を使用してください。詳細については、HTTP仕様の 安全なメソッド を参照してください。
警告
ManyToManyField
属性と逆リレーションを通じて get_or_create()
を使うことができます。この場合、クエリはリレーションのコンテキスト内で制限されます。一貫して使用しないと、整合性の問題が発生する可能性があります。
下記のモデルでは、:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
get_or_create()
は Book の chapters フィールドを通して使うことができますが、その本のコンテキスト内でしか取得できません:
>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError
この現象は、"Ulysses "という本を通して "Chapter 1" を取得、または作成しようとしているために起こっています。しかし、そのいずれもできません。リレーションはその章を取得できません。なぜなら、その章はその本に関連していないからです。また、 title
フィールドは一意でなければならないので、作成することもできません。
update_or_create()
¶
-
update_or_create
(defaults=None, create_defaults=None, **kwargs)¶
-
aupdate_or_create
(defaults=None, create_defaults=None, **kwargs)¶
非同期バージョン: aupdate_or_create()
与えられた kwargs
でオブジェクトを更新し、必要に応じて新しいオブジェクトを作成する便利なメソッドです。 create_defaults
と defaults
はどちらも (field, value) のペアの辞書です。 create_defaults
と defaults
の値はどちらも呼び出し可能オブジェクトです。 defaults
はオブジェクトを更新する際に使用され、create_defaults
はオブジェクトを作成する際に使用されます。もし create_defaults
が指定されなかった場合、 defaults
が作成操作に使用されます。
(Object, created) のタプルを返します。"Object"は受け取ったものか更新したものです。そして"created"はそのObjectが更新されたものかどうかのBooleanです。
update_or_create
メソッドは、与えられた kwargs
に基づいてデータベースからオブジェクトを取得しようとします。一致するオブジェクトが見つかった場合、 defaults
辞書に渡されたフィールドを更新します。
これは定型的なコードへのショートカットです。たとえば次のようなものです:
defaults = {"first_name": "Bob"}
create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
try:
obj = Person.objects.get(first_name="John", last_name="Lennon")
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {"first_name": "John", "last_name": "Lennon"}
new_values.update(create_defaults)
obj = Person(**new_values)
obj.save()
モデル内のフィールドの数が増えるにつれて、このパターンはかなり扱いにくくなります。上記の例は、 update_or_create()
を使って次のように書き換えることができます:
obj, created = Person.objects.update_or_create(
first_name="John",
last_name="Lennon",
defaults={"first_name": "Bob"},
create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)
kwargs
で渡された名前がどのように解決されるかについては get_or_create()
を参照してください。
上記の get_or_create()
で説明したように、このメソッドは、データベースレベルで一意性が強制されていない場合、複数の行が同時に挿入される競合状態に陥りがちです。
get_or_create()
や create()
と同様に、手動で指定した主キーを使用していて、オブジェクトを作成する必要があるが、そのキーが既にデータベースに存在する場合、 IntegrityError
が発生します。
古いバージョンでは Model.save()
の呼び出し時に update_or_create()
が update_fields
を指定していませんでした。
create_defaults
引数が追加されました。
bulk_create()
¶
-
bulk_create
(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)¶
-
abulk_create
(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)¶
非同期バージョン: abulk_create()
このメソッドは、指定されたオブジェクトのリストを効率的な方法でデータベースに挿入し (通常、オブジェクトの数にかかわらずクエリは 1 回だけです)、作成されたオブジェクトを指定された順序でリストとして返します:
>>> objs = Entry.objects.bulk_create(
... [
... Entry(headline="This is a test"),
... Entry(headline="This is only a test"),
... ]
... )
しかし、これにはいくつかの注意点があります:
モデルの
save()
メソッドは呼び出されず、pre_save
とpost_save
シグナルは送信されません。複数テーブル継承シナリオの子モデルでは動作しません。
モデルの主キーが
AutoField
で、ignore_conflicts
が False の場合、主キー属性は特定のデータベース (現在のところ PostgreSQL, MariaDB 10.5+, SQLite 3.35+) でしか取得できません。他のデータベースではセットされません。多対多のリレーションシップでは動作しません。
これは
objs
をリストにキャストし、それがジェネレータであればobjs
を完全に評価します。このキャストにより、手動で主キーを指定したオブジェクトを最初に挿入できるように、すべてのオブジェクトを検査できます。ジェネレータ全体を一度に評価することなく、オブジェクトを一括して挿入したい場合は、オブジェクトに手動で指定した主キーがない限り、このテクニックを使用できます:from itertools import islice batch_size = 100 objs = (Entry(headline="Test %s" % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
batch_size
パラメータは、1回のクエリでいくつのオブジェクトを作成するかを制御します。デフォルトでは、すべてのオブジェクトを 1 回のクエリで作成します。ただし、SQLite ではクエリごとに最大 999 個の変数が使用されます。
これをサポートしているデータベース(Oracleを除くすべてのデータベース)では、 ignore_conflicts
パラメータを True
に設定すると、一意な値の重複などの制約に違反する行の挿入の失敗を無視するようになります。
これをサポートしているデータベース(Oracleを除くすべてのデータベース)では、 update_conflicts
パラメータを True
に設定すると、行の挿入が競合して失敗したときに update_fields
を更新するようになります。PostgreSQL と SQLite では、 update_fields
に加えて、競合する可能性のある unique_fields
のリストを指定する必要があります。
パラメータ ignore_conflicts
を有効にすると、各モデルのインスタンスに主キーを指定できなくなります(データベースが通常サポートしている場合)。
古いバージョンでは、update_conflicts
パラメータを有効にすると、各モデルインスタンスに主キーを指定できませんでした。
警告
MySQL と MariaDB では、 ignore_conflicts
パラメータを True
に設定すると、重複キー以外の特定の種類のエラーが警告に変わります。Strict モードでも同様です。たとえば、無効な値やnull制約違反などです。詳細は MySQL documentation と MariaDB documentation を参照してください。
bulk_update()
¶
-
bulk_update
(objs, fields, batch_size=None)¶
-
abulk_update
(objs, fields, batch_size=None)¶
非同期バージョン: abulk_update()
このメソッドは、通常1回のクエリで、指定されたモデルインスタンスの指定されたフィールドを効率的に更新し、更新されたオブジェクトの数を返します:
>>> objs = [
... Entry.objects.create(headline="Entry 1"),
... Entry.objects.create(headline="Entry 2"),
... ]
>>> objs[0].headline = "This is entry 1"
>>> objs[1].headline = "This is entry 2"
>>> Entry.objects.bulk_update(objs, ["headline"])
2
QuerySet.update()
は変更を保存するために使用されるので、モデルのリストをイテレートしてそれぞれ save()
を呼び出すよりも効率的ですが、いくつかの注意点があります:
- モデルの主キーは更新できません。
- 各モデルの
save()
メソッドは呼び出されず、pre_save
とpost_save
シグナルは送信されません。 - 多数の行の多数のカラムを更新する場合、生成されるSQLは非常に大きくなる可能性があります。これを避けるには、適切な
batch_size
を指定します。 - 複数テーブル継承の継承元に定義されたフィールドを更新すると、継承元ごとに追加のクエリが発生します。
- 独立した1つのバッチ内に重複がある場合、そのバッチの最初のインスタンスだけが更新されます。
- 関数が返す更新されたオブジェクトの数は、渡されたオブジェクトの数より少ない場合があります。これは、渡されたオブジェクトが重複して同じバッチで更新されたり、オブジェクトがデータベースに存在しなくなるような競合状態が発生したりすることが原因です。
batch_size
パラメータは、1回のクエリで保存されるオブジェクトの数を制御します。クエリで使用できる変数の数に制限がある SQLite と Oracle を除いて、デフォルトではすべてのオブジェクトを一括で更新します。
count()
¶
-
count
()¶
-
acount
()¶
非同期バージョン: acount()
QuerySet
にマッチするデータベース内のオブジェクトの数を整数で返します。
実装例:
# Returns the total number of entries in the database.
Entry.objects.count()
# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains="Lennon").count()
count()
呼び出しは裏で SELECT COUNT(*)
を実行するので、すべてのレコードを Python オブジェクトに読み込んで、その結果に対して len()
を呼び出すのではなく、常に count()
を使うべきです(オブジェクトをメモリに読み込む必要がある場合は別です、その場合は len()
の方が高速です)。
もし QuerySet
に含まれるアイテムの数が必要で、かつそこからモデルインスタンスを取得する場合 (たとえば、それをイテレートする場合) は、おそらく len(queryset)
を使用する方が効率的でしょう。count()
のように余分なデータベースクエリが発生することがないからです。
クエリセットがすでに完全に取得されている場合、 count()
は余計なデータベースクエリを実行するのではなく、その長さを使用します。
in_bulk()
¶
-
in_bulk
(id_list=None, *, field_name='pk')¶
-
ain_bulk
(id_list=None, *, field_name='pk')¶
非同期バージョン: ain_bulk()
フィールド値のリスト (id_list
) とそれらの値の field_name
を受け取り、各値を与えられたフィールド値を持つオブジェクトのインスタンスにマッピングした辞書を返します。 django.core.exceptions.ObjectDoesNotExist
例外が in_bulk
によって発生することはありません。つまり、インスタンスにマッチしない id_list
値は無視されます。 id_list
が指定されなかった場合、クエリセット内の全てのオブジェクトが返されます。フィールド名 field_name
は一意なフィールドか、(distinct()
で指定されたフィールドが一つしかない場合は) 区別されたフィールドでなければなりません。デフォルトは主キーです。
例:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}
in_bulk()
に空のリストを渡すと、空の辞書が返されます。
iterator()
¶
-
iterator
(chunk_size=None)¶
-
aiterator
(chunk_size=None)¶
非同期バージョン: aiterator()
( クエリを実行して ) QuerySet
を評価し、その結果に対するイテレータ (PEP 234 を参照) を返します。非同期バージョンの aiterator
を呼び出した場合は、非同期イテレータ (PEP 492 を参照) を返します。
クエリセット QuerySet
は通常、結果を内部的にキャッシュするので、繰り返し評価しても追加のクエリが発生することはありません。一方、 iterator()
は QuerySet
レベルでのキャッシュを行わずに、結果を直接読み込みます (内部的には、デフォルトのイテレータは iterator()
を呼び出し、戻り値をキャッシュします)。一度しかアクセスする必要のない大量のオブジェクトを返す QuerySet
では、この方がパフォーマンスが向上し、メモリを大幅に削減できます。
すでに評価された クエリセット
に対して iterator()
を使用すると、クエリを再度評価することになるので注意してください。
chunk_size
が与えられている限り、 iterator()
は以前の prefetch_related()
の呼び出しと互換性があります。より大きな値を指定すると、より少ないクエリでプリフェッチを行う必要がありますが、その代償としてメモリの使用量が大きくなります。
以前の prefetch_related()
呼び出しによる aiterator()
のサポートが追加されました。
データベースによっては(例えばOracleや SQLite )、SQLの IN
句の最大項数が制限されている場合があります。そのため、この制限値以下の値を使用する必要があります。(特に、2つ以上のリレーションにまたがってプリフェッチを行う場合、chunk_size
は、プリフェッチされた各リレーションに対して予測される結果の数が制限を下回る程度に小さくする必要があります)。
クエリセットがリレーション先のオブジェクトをプリフェッチしない限り、 chunk_size
に何も値を指定しないと、 Django は暗黙のデフォルト値 2000 を使います。
データベースのバックエンドによっては、クエリの結果は一度に読み込まれるか、サーバーサイドのカーソルを使ってデータベースからストリーミングされます。
サーバーサイドカーソルとともに使う¶
Oracle と PostgreSQL はサーバーサイドカーソルを使用して、結果セット全体をメモリに読み込むことなくデータベースから結果をストリームします。
Oracle データベースドライバは常にサーバーサイドカーソルを使用します。
サーバーサイドカーソルでは、chunk_size
パラメータはデータベースドライバレベルでキャッシュする結果の数を指定します。より大きなチャンクをフェッチすることで、データベースドライバとデータベース間の往復回数を減らすことができます。
PostgreSQLでは、サーバーサイドカーソルは DISABLE_SERVER_SIDE_CURSORS
設定が False
の場合のみ使用されます。トランザクションプーリングモードで構成された接続プーラを使用している場合は トランザクションプールとサーバーサイドカーソル を参照してください。サーバーサイドカーソルが無効な場合、動作はサーバーサイドカーソルをサポートしていないデータベースと同じです。
サーバーサイドカーソルなしで使う¶
MySQL は結果のストリーミングをサポートしていないので、Python データベースドライバは結果セット全体をメモリに読み込みます。結果セットはその後、データベースアダプタによって PEP 249 で定義されている fetchmany()
メソッドを使用して Python の行オブジェクトに変換されます。
SQLite は fetchmany()
を使用してバッチで結果を取得できますが、SQLite は接続内のクエリ間の分離を提供していないため、イテレートするテーブルに書き込む際には注意が必要です。詳細は QuerySet.iterator() を使用する際の分離の問題 を参照してください。
chunk_size
パラメータは Django がデータベースドライバから取得するバッチのサイ ズを制御します。バッチを大きくすると、データベースドライバとの通信のオーバヘッ ドが減りますが、その分メモリ消費量が少し増えます。
クエリセットがリレーション先のオブジェクトをプリフェッチしない限り、 chunk_size
に何も値を与えない場合、 Django は暗黙のデフォルト値である 2000 を使うことになります。この値は、 psycopg メーリングリスト で計算された値です:
テキストデータと数値データが混在した10~20列の行を想定すると、2000行で100KB以下のデータを取得することになります。これは、転送される行数と、ループが早期に終了した場合に破棄されるデータとの間の良い妥協点だと思われます。
latest()
¶
-
latest
(*fields)¶
-
alatest
(*fields)¶
非同期バージョン: alatest()
指定されたフィールドに基づいて、テーブル内の最新のオブジェクトを返します。
この例では、 pub_date
フィールドに従って、テーブル内の最新の Entry
を返します:
Entry.objects.latest("pub_date")
また、複数のフィールドから最新のものを選択することもできます。たとえば2つのエントリが同じ pub_date
を持つ場合に、最も早い expire_date
を持つ Entry
を下記のように選択できます:
Entry.objects.latest("pub_date", "-expire_date")
'-expire_date'
の負の符号は、expire_date
を 降順 でソートすることを意味します。 latest()
は最後の結果を取得するので、 expire_date
が最も古い Entry
が選択されます。
モデルの Meta が get_latest_by
を指定している場合、 earliest()
や latest()
の引数を省略できます。 get_latest_by
で指定されたフィールドがデフォルトで使用されます。
get()
と同様に、 earliest()
と latest()
は与えられたパラメータを持つオブジェクトが存在しない場合、 DoesNotExist
を発生させます。
なお、earliest()
と latest()
は単に利便性と可読性のために存在しています。
earliest()
と latest()
は null の日付を持つインスタンスを返すことがあります。
ソートはデータベースに委譲されるため、異なるデータベースを使用している場合、NULL値を許可するフィールドの結果は異なる順序になる可能性があります。たとえば、PostgreSQLとMySQLはnull値をnull値でない値よりも上位にあるかのようにソートしますが、SQLiteはその逆です。
下記のように、null 値をフィルタリングしたいこともあるでしょう:
Entry.objects.filter(pub_date__isnull=False).latest("pub_date")
earliest()
¶
-
earliest
(*fields)¶
-
aearliest
(*fields)¶
非同期バージョン: aearliest()
向きが変わる以外は latest()
のように動作します。
first()
¶
-
first
()¶
-
afirst
()¶
非同期バージョン: afirst()
クエリセットにマッチする最初のオブジェクトを返します。マッチするオブジェクトがない場合は None
を返します。QuerySet
にソートが定義されていない場合、クエリセットは自動的にプライマリキーでソートされます。これは order_by() と一緒に使う で説明されているように、アグリゲーション(集計)の結果に影響を与える可能性があります。
実装例:
p = Article.objects.order_by("title", "pub_date").first()
first()
は便利なメソッドであることに注意してください。以下のコードサンプルは上記の例と等価です:
try:
p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
p = None
aggregate()
¶
-
aggregate
(*args, **kwargs)¶
-
aaggregate
(*args, **kwargs)¶
非同期バージョン: aaggregate()
QuerySet
に対して計算された集計値 (平均、合計など) の辞書を返します。 aggregate()
の各引数は、返却される辞書に含まれる値を指定します。
Django が提供する集計関数は以下の Aggregation Functions で説明されています。 集計は クエリ式 でもあるので、集計を他の集計や値と組み合わせて複雑な集計を作ることができます。
キーワード引数を使用して指定されたアグリゲーション(集計)は、アノテーションの名前としてキーワードを使用します。 無名の引数には、集計関数の名前と集約されるモデルフィールドに基づいて生成された名前が付けられます。複雑な集計では無名の引数を使用することはできず、エイリアスとしてキーワード引数を指定する必要があります。
たとえば、ブログエントリーを扱う場合、下記のように、ブログエントリーを投稿した著者の数を知りたいことがあるでしょう:
>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry"))
{'entry__count': 16}
キーワード引数を使用して集計関数を指定すると、返される集計値の名前を制御できます:
>>> Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 16}
集計処理についての深い議論については、 アグリゲーションについてのトピックガイド を確認してください。
exists()
¶
-
exists
()¶
-
aexists
()¶
非同期バージョン: aexists()
戻り値は QuerySet
に結果が含まれていれば True
を、含まれていなければ False
を返します。これは可能な限りシンプルで高速な方法でクエリを実行しようとしますが、通常の QuerySet
クエリとほぼ同じクエリを実行します。
exists()
は QuerySet
に含まれるオブジェクトの存在に関連する検索、特に大きな QuerySet
の検索に便利です。
クエリセットに項目が含まれているかどうかを調べるには、次のようにします:
if some_queryset.exists():
print("There is at least one object in some_queryset")
これは以下のコードより高速です:
if some_queryset:
print("There is at least one object in some_queryset")
...しかしそれほど大きな差はありません(したがって、効果を感じるには大きなクエリセットが必要です)。
さらに、some_queryset
がまだ評価されていないが、いずれ評価されることがわかっている場合、some_queryset.exists()
を使用すると、結果を取得してから返されたかどうかをチェックする bool(some_queryset)
を使用するよりも、全体的な作業量(存在チェックのためのクエリ1回と、後で結果を取得するためのクエリ1回)が増えます。
contains()
¶
-
contains
(obj)¶
-
acontains
(obj)¶
非同期バージョン: acontains()
QuerySet
に obj
が含まれていれば True
を、含まれていなければ False
を返します。これは、可能な限りシンプルで高速な方法でクエリを実行しようとします。
contains()
は、特に大きな QuerySet
のコンテキストにおいて、 QuerySet
内のオブジェクトの所属関係をチェックするのに便利です。
クエリセットに特定の項目が含まれているかどうかを確認するには、次のようにします:
if some_queryset.contains(obj):
print("Entry contained in queryset")
これは、クエリセット全体を評価し、イテレートする必要がある以下の方法よりも高速です:
if obj in some_queryset:
print("Entry contained in queryset")
exists()
と同様に、some_queryset
がまだ評価されていないが、いずれ評価されることがわかっている場合、some_queryset.contains(obj)
を使用すると、追加のデータベースクエリを行うことになり、通常は全体的なパフォーマンスが低下します。
update()
¶
-
update
(**kwargs)¶
-
aupdate
(**kwargs)¶
非同期バージョン: aupdate()
指定したフィールドに対して SQL の UPDATE クエリを実行し、マッチした行の数を返します (一部の行が既に新しい値を持っている場合は、更新された行の数と一致しないことがあります)。
たとえば、2010年に公開されたすべてのブログエントリーのコメントをオフにするには、次のようにします:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(これは Entry
モデルに pub_date
と comments_on
フィールドがあると仮定しています)。
複数のフィールドを更新できます。たとえば、以下のコードでは comments_on
フィールドと headline
フィールドを更新しています:
>>> Entry.objects.filter(pub_date__year=2010).update(
... comments_on=False, headline="This is old"
... )
update()
メソッドは即座に適用されます。更新される QuerySet
の唯一の制限は、モデルのメインテーブルのカラムのみを更新することができ、リレーション先のモデルのカラムを更新することはできないということです。たとえば、このようなことはできません:
>>> Entry.objects.update(blog__name="foo") # Won't work!
リレーション先のフィールドに基づくフィルタリングは可能です:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
スライスが取られたり、それ以外の理由でこれ以上フィルタリングできなくなった QuerySet
に対しては update()
を呼び出すことはできません。
update()
メソッドは、影響を受ける行の数を返します:
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
>>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132
レコードを更新するだけで、モデルオブジェクトに対して何もする必要がない場合、最も効率的なアプローチは、モデルオブジェクトをメモリに読み込むのではなく、 update()
を呼び出すことです。たとえば、次のようにす書く代わりに、:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
...次のように書きます:
Entry.objects.filter(id=10).update(comments_on=False)
また、update()
を使用することで、オブジェクトを読み込んでから save()
を呼び出すまでの短い間にデータベース内で何かが変更されてしまう競合状態を防ぐことができます。
最後に、 update()
は SQL レベルで更新を行うので、モデル上の save()
メソッドを呼び出したり、 pre_save
や post_save
シグナル ( Model.save()
を呼び出した結果発生するシグナル) を発したりしないことに注意してください。カスタム save()
メソッドを持つモデルのレコードを更新したい場合は、次のようにループして save()
を呼び出します:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
ソートされたクエリセット¶
order_by()
と update()
の連結は MariaDB と MySQL でのみサポートされており、異なるデータベースでは無視されます。これは、一意なフィールドを指定された順序で矛盾なく更新する場合に便利です。たとえば次のようにします:
Entry.objects.order_by("-number").update(number=F("number") + 1)
注釈
order_by()
句がアノテーション、継承されたフィールド、リレーション先のルックアップを含んでいる場合、order_by()
句は無視されます。
delete()
¶
-
delete
()¶
-
adelete
()¶
非同期バージョン: adelete()
QuerySet
内のすべての行に対して SQL による DELETE クエリを実行し、削除されたオブジェクトの数とオブジェクトの種類ごとの削除数を辞書として返します。
delete()
は即座に適用されます。スライスが取られたり、それ以外の理由でこれ以上フィルタリングできなくなった QuerySet
に対しては delete()
を呼び出すことはできません。
たとえば、特定のブログ内のすべてのエントリを削除するには、:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})
デフォルトでは、 Django の ForeignKey
は SQL の制約 ON DELETE CASCADE
をエミュレートします。つまり、削除されるオブジェクトを指す外部キー を持つオブジェクトは一緒に削除されます。たとえば、次のようになります:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})
このカスケードの動作は、ForeignKey
に対する on_delete
属性によってカスタマイズできます。
delete()
メソッドは一括削除を行い、モデルの delete()
メソッドを呼び出しません。しかし、削除されたオブジェクト (カスケード削除を含む) に対して pre_delete
と post_delete
シグナルを発行します。
Django はシグナルを送ったり、カスケードを処理したりするために、オブジェクトをメモリにフェッチする必要があります。しかし、カスケードもシグナルもない場合、 Django は高速な経路をとり、メモリにフェッチせずにオブジェクトを削除するかもしれ ません。大きな削除の場合、メモリ使用量を大幅に減らすことができます。クエリの実行量も減ります。
on_delete
DO_NOTHING
に設定されている外部キーは、削除の際に fast-path を取ることを防ぎません。
オブジェクトの削除で生成されるクエリは、実装の詳細部分であり、変更される可能性があることに注意してください。
as_manager()
¶
-
classmethod
as_manager
()¶
QuerySet
のメソッドをコピーした Manager
のインスタンスを返すクラスメソッドです。詳細は QuerySet のメソッドで、マネージャを生成する を参照してください。
このセクションの他の項目とは異なり、クエリを実行しないため、非同期バージョンがないことに注意してください。
explain()
¶
-
explain
(format=None, **options)¶
-
aexplain
(format=None, **options)¶
非同期バージョン: aexplain()
QuerySet
の実行計画文字列を返します。この実行計画は、使用するインデックスや結合を含め、データベースがどのようにクエリを実行するかの詳細を示します。これらの詳細を知ることで、遅いクエリのパフォーマンスを向上させることができます。
たとえば、PostgreSQLを使う場合:
>>> print(Blog.objects.filter(title="My Blog").explain())
Seq Scan on blog (cost=0.00..35.50 rows=10 width=12)
Filter: (title = 'My Blog'::bpchar)
出力はデータベースによって大きく異なります。
explain()
は Oracle を除くすべての組み込みデータベースバックエンドでサポートされています。これは Oracle での実装が一筋縄ではいかないからです。
format
パラメータは、データベースのデフォルトの出力形式 (通常はテキストベース) から変更します。PostgreSQLは 'TEXT'
、 'JSON'
、 'YAML'
、 'XML'
フォーマットをサポートしています。MariaDB と MySQL は 'TEXT'
( 'TRADITIONAL'
とも呼びます) と 'JSON'
形式をサポートしています。MySQL 8.0.16+ では、改良された TREE'
フォーマットもサポートしています。これは PostgreSQL の 'TEXT'
出力に似ており、サポートされていればデフォルトで使用されます。
データベースによっては、クエリに関する詳細な情報を返すフラグを受け付けるものがあります。これらのフラグをキーワード引数として渡してください。たとえば、PostgreSQLを使用している場合:
>>> print(Blog.objects.filter(title="My Blog").explain(verbose=True, analyze=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms
データベースによっては、フラグによってクエリが実行され、データベースに悪影響を及ぼす可能性があります。たとえば、MariaDB、MySQL 8.0.18+、PostgreSQLでサポートされている ANALYZE
フラグは、 SELECT
クエリであっても、トリガがある場合や関数が呼び出された場合にデータを変更してしまう可能性があります。
Field
ルックアップ¶
フィールドルックアップは SQL の WHERE
句の内容を指定する方法です。これらは filter()
、 exclude()
、 get()
メソッドのキーワード引数として指定します。
概要については モデルとデータベースクエリのドキュメント を参照してください。
Django の組み込みルックアップを以下に示します。モデルフィールドのために カスタムルックアップ を書くこともできます。
利便性のために、ルックアップタイプが指定されていない場合( Entry.objects.get(id=14)
のように)、ルックアップタイプは exact
とみなされます。
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;
MySQL における比較
MySQL では、データベースのテーブルの「照合順序」の設定で、exact
比較が大文字小文字を区別するかどうかを決めます。これはデータベースの設定で、 Django の設定ではありません。大文字小文字を区別して比較するように MySQL のテーブルを設定することは可能ですが、いくつかの トレードオフが伴います。これについては データベース ドキュメントの 照合順序のセクション を参照してください。
iexact
¶
大文字小文字を区別しない完全一致。比較に指定された値が None
の場合、SQL の NULL
と解釈されます (詳細は isnull
を参照してください)。
実装例:
Blog.objects.get(name__iexact="beatles blog")
Blog.objects.get(name__iexact=None)
これは下記のSQL文と等価です。
SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;
最初のクエリは 'Beatles Blog'
, 'beatles blog'
, 'BeAtLes BLoG'
などにマッチすることに注意してください。
SQLite ユーザーの場合
SQLite バックエンドで非 ASCII 文字列を使用する場合は、文字列の比較に関する データベースのノート に注意してください。SQLiteは非ASCII文字列に対して大文字小文字を区別しないマッチングを行いません。
contains
¶
大文字小文字を区別し、文字列を含むかをチェックします。
実装例:
Entry.objects.get(headline__contains="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline LIKE '%Lennon%';
'Lennon honored today'
という見出しにはマッチしますが、 'lennon honored today'
という見出しにはマッチしないことに注意してください。
SQLite ユーザーの場合
SQLite は大文字小文字を区別する LIKE
ステートメントをサポートしていません。詳細は データベースに関する注意事項 を参照してください。
icontains
¶
大文字小文字を区別せずに文字列を含むかをチェックします。
実装例:
Entry.objects.get(headline__icontains="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline ILIKE '%Lennon%';
SQLite ユーザーの場合
SQLite バックエンドで非 ASCII 文字列を使用する場合は、文字列の比較に関する データベースに関する注意事項 に注意してください。
in
¶
指定されたイテラブル(多くの場合、リスト、タプル、クエリセット)内に含まれるかをチェックします。あまり使われませんが、(イテラブルである)文字列は使用可能です。
例:
Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in="abc")
これは下記のSQL文と等価です。
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
リテラル値のリストを提供する代わりに、クエリセットを使用して以下のように値のリストを動的に評価することもできます:
inner_qs = Blog.objects.filter(name__contains="Cheddar")
entries = Entry.objects.filter(blog__in=inner_qs)
このクエリセットは下記のようなサブクエリ内の SELECT 文として評価されます:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
もし values()
や values_list()
の結果の クエリセット
を __in
ルックアップの値として渡す場合は、結果の中の1つのフィールドだけを抽出するようにする必要があります。たとえば、次のようにします(ブログ名でフィルタリングする場合):
inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
下記の例では例外が発生します。内側のクエリは2つのフィールド値を抽出しようとしているからです:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
パフォーマンスに関する注意事項
ネストされたクエリの使用には注意し、データベースサーバーのパフォーマンス特性を理解しましょう (疑わしい場合はベンチマークを使用しましょう!)。データベースバックエンドによっては、特に MySQL はネストされたクエリをあまり最適化しません。そのような場合は、値のリストを抽出してから 2 番目のクエリに渡すほうが効率的です。つまり、1つのクエリではなく、下記のように2つのクエリを実行するのです。
values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
最初のクエリを強制的に実行するために、Blog QuerySet
を list()
呼び出しで囲んでいることに注意してください。これがないと、ネストされたクエリが実行されてしまうからです。これは QuerySet は遅延評価される ためです。
gt
¶
~~より大きい(greater than)。
実装例:
Entry.objects.filter(id__gt=4)
これらは SQL で言う下記と同等です:
SELECT ... WHERE id > 4;
gte
¶
~~以上(greater than or equal to)。
lt
¶
~~未満(less than)。
lte
¶
~~以下(less than equal to)。
startswith
¶
大文字と小文字を区別して、指定された文字列から始まるかどうかをチェックします。
実装例:
Entry.objects.filter(headline__startswith="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite は大文字小文字を区別する LIKE
文をサポートしていません。 SQLite では startswith
は istartswith
のように動作します。
istartswith
¶
大文字と小文字を区別せず、指定された文字列から始まるかどうかをチェックします。
実装例:
Entry.objects.filter(headline__istartswith="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline ILIKE 'Lennon%';
SQLite ユーザーの場合
SQLite バックエンドで非 ASCII 文字列を使用する場合は、文字列の比較に関する データベースに関する注意事項 に注意してください。
endswith
¶
大文字と小文字を区別して、指定された文字列で終わるかどうかをチェックします。
実装例:
Entry.objects.filter(headline__endswith="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline LIKE '%Lennon';
SQLite ユーザーの場合
SQLite は大文字小文字を区別する LIKE
文をサポートしていません。 endswith
は SQLite の iendswith
のように動作します。詳しくは データベースに関する注意事項 のドキュメントを参照してください。
iendswith
¶
大文字と小文字を区別せず、指定された文字列で終わるかどうかをチェックします。
実装例:
Entry.objects.filter(headline__iendswith="Lennon")
これらは SQL で言う下記と同等です:
SELECT ... WHERE headline ILIKE '%Lennon'
SQLite ユーザーの場合
SQLite バックエンドで非 ASCII 文字列を使用する場合は、文字列の比較に関する データベースに関する注意事項 に注意してください。
range
¶
範囲のチェック(~~を含む)。
実装例:
import datetime
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
が使えるところならどこでも使えます。日付、数字、そして文字でも使えます。
警告
日付で DateTimeField
をフィルタリングすると、最終日のアイテムは含まれません。もし pub_date
が DateTimeField
であった場合、上記の式はこのようなSQLになります:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
一般的に言って、日付と日時を混在させることはできません。
date
¶
datetime フィールドの値を date としてキャストします。追加のフィールドルックアップを連結できます。 date 値を取ります。
実装例:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
USE_TZ
が True
の場合、フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これには データベースのタイムゾーン定義 が必要です。
year
¶
日付フィールドとdatetimeフィールドにおける、"年" の完全一致。追加のフィールドルックアップを連結できます。年を整数で指定します。
実装例:
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)
これらは SQL で言う下記と同等です:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
iso_year
¶
日付フィールドとdatetimeフィールドにおける、ISO 8601の週番号と年との完全一致。追加のフィールドルックアップを連結できます。年を整数で指定します。
実装例:
Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
month
¶
日付フィールドおよびdatetimeフィールドにおける、"月" の完全一致。追加のフィールドルックアップを連結できます。1 (1月) から 12 (12月) までの整数を指定します。
実装例:
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
これらは SQL で言う下記と同等です:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
day
¶
日付フィールドとdatetimeフィールドにおける、"日" の完全一致。追加のフィールドルックアップを連結できます。日を整数で指定します。
実装例:
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
これらは SQL で言う下記と同等です:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(正確なSQL構文はデータベースエンジンによって異なります)。
これは、1 月 3 日、7 月 3 日など、pub_date が月の 3 日目のレコードに一致します。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
week
¶
日付フィールドおよびdatetimeフィールドにおける、 ISO-8601 に従った週番号 (1~52または53) を返します。すなわち、週は月曜日から始まり、最初の週にはその年の最初の木曜日が含まれます。
実装例:
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
week_day
¶
日付フィールドとdatetimeフィールドにおける "曜日" の一致。追加のフィールドルックアップを連結できます。
1 (日曜日) から 7 (土曜日) までの曜日を表す整数値を指定します。
実装例:
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
pub_date
が月曜日(週の2日目)のレコードは、月や年に関係なくマッチすることに注意してください。 週の曜日のインデックスは1日目が日曜日、7日目が土曜日です。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
iso_week_day
¶
日付フィールドおよび datetime フィールドにおける、ISO 8601 曜日との完全一致。追加のフィールドルックアップを連結できます。
1(月曜日)から7(日曜日)までの曜日を表す整数値を取ります。
実装例:
Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
pub_date
が月曜日(週の1日目)のレコードは、月や年に関係なくマッチすることに注意してください。週の曜日のインデックスは1日目が月曜日、7日目が日曜日です。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
quarter
¶
日付および datetime フィールドにおける、"四半期" の一致。追加のフィールドルックアップを連結できます。年の四半期を表す 1 から 4 までの整数値を指定します。
第2四半期(4月1日から6月30日まで)のエントリーを検索する例:
Entry.objects.filter(pub_date__quarter=2)
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
time
¶
datetime フィールドの場合、値を time としてキャストします。追加のフィールドルックアップを連結できます。 datetime.time
値を取ります。
実装例:
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(このルックアップに等価なSQLの例はありません。これは、関連するクエリの実装がデータベースエンジンによって異なるためです)。
USE_TZ
が True
の場合、フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これには データベースのタイムゾーン定義 が必要です。
hour
¶
datetimeフィールドとtimeフィールドにおける、"時(hour)" の完全一致。追加のフィールドルックアップを連結できます。0 から 23 までの整数を指定します。
実装例:
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)
これらは SQL で言う下記と同等です:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
minute
¶
datetime フィールドと time フィールドにおける、"分" の完全一致。追加のフィールドルックアップを連結できます。0 から 59 までの整数を指定します。
実装例:
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)
これらは SQL で言う下記と同等です:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
second
¶
datetime および time フィールドにおける、"秒" の完全一致。追加のフィールドルックアップを連結できます。0 から 59 までの整数を指定します。
実装例:
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)
これらは SQL で言う下記と同等です:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(正確なSQL構文はデータベースエンジンによって異なります)。
USE_TZ
が True
の場合、日付フィールドはフィルタリングの前にカレントタイムゾーンに変換されます。これにはデータベースの タイムゾーン定義 が必要です。
isnull
¶
"True" または "False" を受け取り、それぞれ IS NULL
と IS NOT NULL
の SQL クエリに対応します。
実装例:
Entry.objects.filter(pub_date__isnull=True)
これらは SQL で言う下記と同等です:
SELECT ... WHERE pub_date IS NULL;
regex
¶
大文字小文字を区別する正規表現マッチ。
正規表現の構文は、使用するデータベースバックエンドのものです。正規表現のサポートが組み込まれていないSQLiteの場合、この機能は(Pythonの)ユーザー定義REGEXP関数によって提供され、正規表現の構文は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
正規表現の構文を渡す際には、生の文字列(例: 'foo'
の代わりに r'foo'
) を使うことを推奨します。
iregex
¶
大文字小文字を区別しない正規表現マッチ。
実装例:
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
集計(Aggregation)関数¶
Django は django.db.models
モジュールで以下の集計関数を提供しています。これらの集計関数の使い方は アグリゲーション(集計)に関するトピックガイド を参照してください。集計関数の作成方法については Aggregate
ドキュメント を参照してください。
警告
SQLite は日付/時刻フィールドの集計をそのままでは扱えません。これは、 SQLite にはネイティブな日付/時刻フィールドが存在せず、Django は現在、テキストフィールドを使っ てこれらの機能をエミュレートしているからです。SQLite で日付/時刻フィールドの集計を使おうとすると、 NotSupportedError
が発生します。
空のクエリセットやグループの場合
集計関数は空の クエリセット
やグループで使用すると None
を返します。たとえば、 Sum
集計関数は、 QuerySet
にエントリが含まれていない場合や、空ではない QuerySet
に含まれる空のグループに対して、 0
の代わりに None
を返します。代わりに別の値を返すには、 default
引数を定義します。 Count
は default
引数をサポートしていないため、 QuerySet
が空の場合は 0
を返します。
すべての集計に共通するパラメータは以下の通りです:
output_field
¶
戻り値の モデルフィールド を表すオプションの引数です。
注釈
複数のフィールドタイプを組み合わせる場合、Django が output_field
を決定できるのは、全てのフィールドタイプが同じ場合だけです。そうでない場合は、 output_field
を自分で指定しなければなりません。
default
¶
オプションの引数で、クエリセット(またはグループ化)にエントリがない場合にデフォルト値として使用する値を指定できます。
**extra
¶
集計によって生成されるSQLに追加のコンテキストを提供できるキーワード引数。
Avg
¶
-
class
Avg
(expression, output_field=None, distinct=False, filter=None, default=None, **extra)¶ 指定した式の平均値を返します。これは、別の
output_field
を指定しない限り、必ず数値となります。- デフォルトのエイリアス:
<field>__avg
- 戻り値の型: 入力が
int
の場合はfloat
を、それ以外の場合は入力フィールドと同じものを、output_field
を指定した場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
を返します。
-
distinct
¶ オプションです。
distinct=True
の場合、Avg
は一意な値の平均値を返します。これは SQL のAVG(DISTINCT <field>)
と等価です。デフォルト値はFalse
です。
- デフォルトのエイリアス:
Count
¶
-
class
Count
(expression, distinct=False, filter=None, **extra)¶ 指定した式で関連付けられたオブジェクトの数を返します。
Count('*')
は SQL のCOUNT(*)
式と等価です。- デフォルトのエイリアス:
<field>__count
- 戻り値の型:
int
-
distinct
¶ オプションです。
distinct=True
の場合、一意なインスタンスのみをカウントします。これは SQL のCOUNT(DISTINCT <field>)
と等価です。デフォルト値はFalse
です。
注釈
default
引数はサポートされていません。- デフォルトのエイリアス:
Max
¶
-
class
Max
(expression, output_field=None, filter=None, default=None, **extra)¶ 指定された式の最大値を返します。
- デフォルトのエイリアス:
<field>__max
- 戻り値の型: 入力フィールドと同じ、または
output_field
が指定されている場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
が返されます。
- デフォルトのエイリアス:
Min
¶
-
class
Min
(expression, output_field=None, filter=None, default=None, **extra)¶ 指定した式の最小値を返します。
- デフォルトのエイリアス:
<field>__min
- 戻り値の型: 入力フィールドと同じ、または
output_field
が指定されている場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
が返されます。
- デフォルトのエイリアス:
StdDev
¶
-
class
StdDev
(expression, output_field=None, sample=False, filter=None, default=None, **extra)¶ 指定した式のデータの標準偏差を返します。
- デフォルトのエイリアス:
<field>__stddev
- 戻り値の型: 入力が
int
の場合はfloat
を、それ以外の場合は入力フィールドと同じものを、output_field
を指定した場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
を返します。
-
sample
¶ オプションです。デフォルトでは
StdDev
は母集団の標準偏差を返します。ただし、sample=True
の場合は、標本の標準偏差が返されます。
- デフォルトのエイリアス:
Sum
¶
-
class
Sum
(expression, output_field=None, distinct=False, filter=None, default=None, **extra)¶ 与えられた式のすべての値の合計を計算します。
- デフォルトのエイリアス:
<field>__sum
- 戻り値の型: 入力フィールドと同じ、または
output_field
が指定されている場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
が返されます。
-
distinct
¶ オプションです。
distinct=True
の場合、Sum
は一意な値の合計を返します。これは SQL のSUM(DISTINCT )
と等価です。デフォルト値はFalse
です。
- デフォルトのエイリアス:
Variance
¶
-
class
Variance
(expression, output_field=None, sample=False, filter=None, default=None, **extra)¶ 指定された式のデータの分散を返します。
- デフォルトのエイリアス:
<field>__variance
- 戻り値の型: 入力が
int
の場合はfloat
を、それ以外の場合は入力フィールドと同じものを、output_field
を指定した場合はoutput_field
を返します。クエリセットまたはグループ化が空の場合はdefault
を返します。
-
sample
¶ オプションです。デフォルトでは
Variance
は母分散を返します。ただし、sample=True
の場合は、標本の分散を返します。
- デフォルトのエイリアス: