Djangoのexcludeで指定のレコードを除外する
- 作成日: 2021-01-12
- 更新日: 2023-12-24
- カテゴリ: Django
Djangoのexclude
PythonのWebフレームワークであるDjango(ジャンゴ)では、QuerySet
というクラスを使ってモデルのレコードを自由に取得することが出来ます。
filter()
やall()
などの代表的なメソッドがQuerySet
のメソッドです。
そのメソッドの中にexclude(エクスクルード)という指定のレコードを除外するメソッドがあります。
このメソッドを使うことでレコードの取得時に特定のデータを除外することが可能になります。
この記事ではこのexclude()
について、具体的に↓を見ていきます。
- exclude()の構造
- exclude()でレコードを除外する
- exclude()のソースコードの解析
exclude()の構造
exclude()
はdjango.db.models.query
モジュール内のQuerySet
クラスのメソッドです。
exclude()
は↓のような構造になっています。
exclude(self, *args, **kwargs)
exclude()
は可変長引数とキーワード引数を取り、返り値として新しく生成したQuerySet
を返します。
引数にはモデルのフィールドをキーワードで指定することが出来ます。
exclude()でレコードを除外する
今回は↓のようなモデルを作成している前提で解説します。
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=64, help_text='名前')
age = models.IntegerField(help_text='年齢')
Person
モデルは人物を表すモデルです。人物名を表すname
フィールドと、年齢を表すage
フィールドを持ちます。
データベースには↓のようなコードでオブジェクトを作成しています。
Person.objects.create(name='Taro', age=20)
Person.objects.create(name='Hanako', age=18)
Person.objects.create(name='Kenta', age=25)
Person.objects.create(name='Tama', age=4)
全部で4件のレコードですね。
このデータベースに対して、特定のレコードを除外して結果を取得したい場合を考えます。
例えばname
が「Kenta」のレコードのみを結果から除外したいとします。
その場合、コードは↓のようになります。
Person.objects.exclude(name='Kenta')
↑のようにexclude()
メソッドのキーワード引数にモデルのフィールド名と値を設定します。
↑の場合、name
フィールドが「Kenta」のレコードが結果から除外されます。
コードの返り値を↓のように出力します。
persons = Person.objects.exclude(name='Kenta')
for person in persons:
print(person.name, person.age)
↑のコードの出力結果は↓のようになります。
Taro 20
Hanako 18
Tama 4
↑の結果を見ると、取得したレコード内に「Kenta」のレコードがありません。
除外されているのがわかります。
containsを使った除外
フィールド名に__contains
をつけることで、そのフィールドの値に対して大文字小文字を区別しない部分一致を行うことが可能です。
例えば↓のコードで初期化したデータベースから、name
に「Ta」が含まれるレコードを除外したいとします。
Person.objects.create(name='Taro', age=20)
Person.objects.create(name='Hanako', age=18)
Person.objects.create(name='Kenta', age=25)
Person.objects.create(name='Tama', age=4)
その場合、コードは↓のようになります。
Person.objects.exclude(name__contains='Ta')
結果を↓のように出力します。
persons = Person.objects.exclude(name__contains='Ta')
for person in persons:
print(person.name, person.age)
データベースがSqlite3の場合は、↑のコードの出力は↓のようになります。
Hanako 18
↑のようにSqlite3をデータベースにしている場合、contains
は大文字小文字を区別しません。
MySQLやMariaDBなどの場合は大文字小文字が区別されます。
MySQLやMariaDBなどで大文字小文字を区別しないようにしたい場合は__icontains
を使います。
exclude()のソースコードの解析
exclude()
はDjangoではどのように実装されているのでしょうか?
↓のコードを見てみます。
内容的にはself._filter_or_exclude(True, args, kwargs)
を呼び出しています。
これはfilter()
メソッド内でも使っていて、共通のメソッドです。
_filter_or_exclude()
は最終的に_filter_or_exclude_inplace()
を呼び出しています。
このメソッド内ではQ
オブジェクトを使ってフィルタリングを行っています。
つまりexclude()
は最終的にQ
オブジェクトでフィルタリングされることがわかります。
Q
オブジェクトは_query.add_q()
に渡されます。
この_query
オブジェクトはdjango.db.models.sql.query
内のQuery
クラスのオブジェクトです。
そのためadd_q()
メソッドはこのQuery
クラスのメソッドです。
add_q()
メソッド内では引数のQ
オブジェクトを使ったSQL文の構築を行います。
Query
クラスで構築されたSQL文が最終的にデータベースに発行されるということみたいです。
おわりに
今回はDjangoのQuerySetのメソッドであるexclude()
を見て見ました。
特定のレコードを除外したい場合はこのexclude()
を使いましょう。
🦝 < 除外してフィルタリングしよう