2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Django]たまに見かけるQオブジェクト

Last updated at Posted at 2022-11-01

Qオブジェクトってなに?

最近、業務中にこんな感じのコードに出会いました。

例文
Contract.objects.filter(Q(price__gt=100)|Q(date__year = 2022))

なんとなくorを使って絞り込みたいの時に使われることは知っていたのですが、もう少し深ぼって調べてみました。

1.ドキュメントによると

Q object (django.db.models.Q) is an object used to encapsulate a collection of keyword arguments. These keyword arguments are specified as in "Field lookups" above.

訳すると、
Qオブジェクトはキーワード引数の集まりをカプセル化するときに使われるオブジェクト。これらのキーワード引数は、上の Field lookups のように指定される。
ということらしいです。よくわからないですね。^^

基本的にfilter(条件,条件)の場合はANDで絞り込まれるますが、ANDではなくORを使って絞り込みたい時にQオブジェクトが役に立つという認識で大丈夫です。

Field lookupsというのは、

Field lookups
example1 = Model.objects.get(question__startswith='Who')
example2 = Model.objects.filter(num__gt = 20)

上の__アンダースコア✖️2の後に続く部分のことです。ここでいうとstartswith,gtのことですね。

要は、Field lookupを使うときにQオブジェクトを組み合わせることで、より柔軟に絞り込みができるということです。Field lookupによる絞り込みとAND(,による区切り),ORがあればある程度のことはできますね。

しかしAND,ORだけだと、ただの和積なのでそんなに柔軟にはなりません。そこでもう一つ、NOT(否定)もちゃんと使えるようになっています。

2.NOT のやり方

NOTを使いたい時は、~を使います。
次のように、Qの前に~をつければ出来上がりです。

否定条件
#Whoから始まる文字列、または、2005年でないという条件にしたいときに
Q(question__startswith='Who') | ~Q(pub_date__year=2005)

3.注意点

Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are "AND"ed together. However, if a Q object is provided, it must precede the definition of any keyword arguments

lookup関数を使うときは、Qオブジェクトを先に書かないと望んだクエリと違うクエリが出されちゃうよということです。もし、Qオブジェクトを後に使った場合は、ORではなくANDで組み合わさることになるので気をつけてください。

OK
#Qが先に来ているので、OK
Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who',
)
NG
#Qが後に来ているので、NG
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

どんなSQLが出されているか

エンジニアとしては、どんなSQLが出されているか知っておくに越したことはないので一応いくつか例を出しておきますね。

example1
Django>
Q(question__startswith='Who') | Q(question__startswith='What')

SQL>
WHERE question LIKE 'Who%' OR question LIKE 'What%'
example2
Django>
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')

参考記事

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?