PUROGU LADESU

ポエムがメインのブログです。

【Django】クエリを作成する

クエリを作成する | Django ドキュメント | Django

データベースからオブジェクトを取得するには、モデルクラスの Manager から QuerySet を作ります。
各モデルは少なくとも一つの Manager を持ち、デフォルトでは objects という名前を持ちます。
SQL 文においては、 QuerySet は SELECT 句、フィルターは WHERE や LIMIT のような絞り込みに用いる句に対応しています。

特定のオブジェクトの取得

Entry.objects.all()
filter() 一致するもの
exclude() 一致しないもの
それぞれメソッドチェーンもできる。

getは条件のデータが存在しない場合、2つ以上マッチした場合は例外を発生する(DoesNotExist, MultipleObjectReturned)
filter()[0]でスライスした場合は、IndexErrorとなる

指定がない場合exactでマッチされる。
iexactは大文字小文字を判別しない。
contains部分一致

リレーションを横断

model__field='zzz'
データがなかった場合、リレーションがなかったのか、値がなかったのか判別できない

pk

ぜんぶ同じ
id_exact=1
id=1
pk=1

F()

クエリの中でモデルフィールドを参照するときに使う
演算も対応。
Entry.objects.filter(number_of_comments__gt=F('field_name') * 2)

アンダースコア2つで連結して、関連モデルのデータを参照できる
F('blog__name')

時間の計算もできる
F('pub_date') + timedelta(days=3)

LIKE

下記のLIKEが使われるクエリでは、%と_はSQLではエスケープされる
iexact, contains, icontains, startswith, istartswith, endswith and iendswith

クエリのキャッシュ

QuerySetはデータベースアクセスを最小限にするために内部キャッシュを持つ
QuerySetを変数に格納しておくと、評価する際にキャッシュが使われる。

queryset = Entry.objects.all() # 一旦格納

QuerySetの一部しか評価されなかった場合、キャッシュは使われない。
全体を一度評価した場合は、その後キャッシュが使われる。
いきなり queryset[5] をするとキャッシュが使われないが、一旦全部取得した後実行するとキャッシュが使われる。

[entry for entry in queryset] # 全てにアクセス

JSONFieldの検索

Noneを指定するとSQLのNULLが格納される。JSONとしてのnullはValue('null')を使う。
検索も同様にSQLのNULLはisnullを使う。

JSON内部の値を検索するにはダブルアンダースコアでチェーンする。
配列にはインデックス番号が指定できる。
データベース製品による挙動の違いに注意。

Dog.objects.filter(data__owner__other_pets__0__name='Fishy')

その他のメソッド
contained_by、has_key、has_keys、has_any_keys

Qオブジェクトを使った複雑な検索

from django.db.models import Q
Q オブジェクトは & や | 演算子を使って結合することができます

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

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

オブジェクトの比較

イコールを使ったオブジェクト同士の比較はプライマリーキーの比較と同等である。

オブジェクトのコピー

組み込みのコピー機能は無いが、pkをNoneにして保存すると新たなpkが生成されるのでコピーと同等である。
blog.pk = None
blog.save()

一括更新

更新できるのはメインのテーブルのみ。関連テーブルは更新できない。
リレーションの外部キーの更新はできるので、関連データのインスタンスを渡す。
F()を使ったフィールドの指定ができるが、joinは使えないので同一テーブルのみ。

Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

関連オブジェクト

関連オブジェクトがある場合のアクセスは、単純に外部キー指定されているフィールドを指定する。
反対に関連オブジェクト側から元のオブジェクトのmanagerにアクセス出来る。
名前xxx_setとなりモデル名は小文字となる。

ForeignKey定義時にrelated_nameオプションを指定している場合、xxx_setはそれで上書きされる。

独自のmanagerを使う場合はmanagerオプションに指定する。
entry_set(manager='entries')

メソッド
add, create, remove, clear, set