DjangoのQオブジェクトの使い方: OR検索、否定

363, 2021-12-08

目次

DjangoのQオブジェクトの使い方

Djangoではfilter()でDBのレコードを検索することができます。
その時にOR検索や否定条件を指定したい時があります。
そういう時はQオブジェクトを使うと簡単にできます

この記事ではDjangoのQオブジェクトについて具体的に解説します。
具体的には↓の項目を見ていきます。

  • Qオブジェクトのインポート方法

  • 普通に検索

  • OR検索

  • AND検索

  • 否定

関連記事

前提とするプロジェクト構造

今回の解説に使用するプロジェクトは↓のようなモデルを持ちます。

from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=255, help_text='記事のタイトル')
    content = models.TextField(max_length=4096, help_text='記事の内容')

Articleという記事を表現するモデルを定義しています。
Articletitlecontentというフィールドを持ちます。
titleには記事のタイトル、contentには記事の内容が保存されます。

それからDBは↓のスクリプトで初期化している前提です。

from myapp.models import Article

for a in Article.objects.all():
    a.delete()

Article.objects.create(title='鳥になりたい', content='')
Article.objects.create(title='猫の額ほど狭い', content='')
Article.objects.create(title='犬になりたい', content='')
Article.objects.create(title='犬も歩けば棒に当たる', content='')
$ python manage.py shell < init.py

検証するDBには合わせて4レコードが挿入されています。
それぞれ鳥や猫、犬などのワードをtitleに含みます。

Qオブジェクトのインポート方法

Qオブジェクトをインポートするには↓のコードを書きます。

from django.db.models import Q

Qオブジェクト自体はquery_utils.pyというモジュールに定義されています。

query_utils - Django

QオブジェクトはNodeを継承したオブジェクトで、Nodeの持つメソッド(add)も合わせて使うことができます。

普通に検索

QオブジェクトをORもANDも行わずに普通に使う方法です。
↓のようにQオブジェクトをフィルターに渡します。

    # 普通に使う
    articles = Article.objects.filter(Q(title__icontains='鳥')).all()
    print([a.title for a in articles])
    # ['鳥になりたい']

Qオブジェクトの引数にはfilter()検索条件と同様のパラメーターを指定します。
↑の場合はtitle__icontainsを指定しています。
これはArticletitleに「鳥」が含まれているか? という条件になります。

Qオブジェクトを渡したfilter()はQオブジェクトの条件でDBを検索します。
↑の場合だと「鳥になりたい」というtitleを持つレコードがヒットしています。

OR検索

QオブジェクトでOR検索する方法です
Qオブジェクトを「|」で繋げるとOR検索になります。
あるいはadd()に「Q.OR」を渡しても同様です。

    # OR検索
    articles = Article.objects.filter(
        Q(title__icontains='鳥') | Q(title__icontains='猫')
    ).all()
    print([a.title for a in articles])
    # ['鳥になりたい', '猫の額ほど狭い']

    # OR検索 その2
    q = Q()
    q.add(Q(title__icontains='鳥'), Q.OR)
    q.add(Q(title__icontains='猫'), Q.OR)

    articles = Article.objects.filter(q).all()
    print([a.title for a in articles])
    # ['鳥になりたい', '猫の額ほど狭い']

↑の前者のOR検索では「Q(title__icontains='鳥') | Q(title__icontains='猫')」という条件を指定しています。
これは「titleに鳥、または猫が含まれる」という条件指定になります。
この条件だとArticletitleに鳥、または猫が含まれるレコードがヒットします。

またQオブジェクトをインスタンス化してqにして、このqのメソッドadd()を呼び出すことでも条件を追加できます(↑の後者のAND検索)。
add()の第1引数にはQオブジェクトで条件を指定します。
そして第2引数には演算子を指定します。
↑の場合だとQ.ORを指定しているので条件はOR検索用になります。

AND検索

QオブジェクトでAND検索する方法です
Qオブジェクトを「&」で繋げるとAND検索になります。

    # AND検索
    articles = Article.objects.filter(
        Q(title__icontains='犬') & Q(title__icontains='棒')
    ).all()
    print([a.title for a in articles])
    # ['犬も歩けば棒に当たる']

    # AND検索 その2
    q = Q()
    q.add(Q(title__icontains='犬'), Q.AND)
    q.add(Q(title__icontains='棒'), Q.AND)

    articles = Article.objects.filter(q).all()
    print([a.title for a in articles])
    # ['犬も歩けば棒に当たる']

↑の前者のAND検索では「犬」と「棒」でAND検索しています。
この条件だとArticletitleに犬と棒が含まれるレコードがヒットします。

またAND検索もQオブジェクトのadd()で指定することができます
↑の後者のAND検索ではQオブジェクトをインスタンス化して、add()メソッドを呼び出しています。
add()の第1引数にはQオブジェクトで条件を指定し、第2引数にはQ.ANDを指定します。
こうすることでadd()で追加していく条件がANDで結合されます。

否定

Qオブジェクトを使うと否定条件も書くことが出来ます
否定にはQオブジェクトに「~」を指定します。

    # 否定
    articles = Article.objects.filter(~Q(title__icontains='犬')).all()
    print([a.title for a in articles])
    # ['鳥になりたい', '猫の額ほど狭い']

↑の場合だと「~Q(title__icontains='犬')」という条件を指定しています。
この条件だと「titleに犬を含まない記事」にレコードがヒットします。
また、この否定演算子はORやANDとも合わせて使うことが可能です。

おわりに

今回はDjangoのQオブジェクトについて解説しました。
Qオブジェクトは複雑な条件を指定して検索したい時に役立つオブジェクトです。
Djangoではわりと頻繁に使われます。
Qオブジェクトの使い方をマスターしておけばきっと役に立つでしょう。

(^ _ ^)

QあんどD

(・ v ・)

QあんどDjangoね



この記事のアンケートを送信する