【django】QuerySetのfilterの使い方まとめ

スポンサーリンク
Django

本記事ではdjangoのQuerySetの関数「filter」について

  • filterの使い方
  • filterによるさまざまな抽出方法(部分一致、以上・未満)
  • 正規表現によるfilterの抽出
  • filterとgetの違い

を解説していきます。

djangoでデータベースに複数のデータを入れていると、抽出するためにfilterはとても便利です。

そのfilterの使い方をまとめてみました。

それぞれを紹介していきます。

filterの使い方

filter関数の使い方を解説していきます。

使い方を簡単に説明すると

Model.objects.filter(field='value')

他のQuerySet関数の使い方と同じように、モデル名.objectsを付けて、最後にfilter()をつけます。

filterの中身は辞書型のように、キーに対して抽出したい値(value)を入力します。

これで使えますが、実際の例も含めて解説していきます。

まず、filterで抽出するためのデータベースを用意していきます。

models.py

from django.db import models

class Sample(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()
    number = models.InterField()

    def __str__(self):
        return u'%s, %s, %s' %(self.title, self.text, self.number)

このmodels.pyはtitleとtextフィールドをもっています。これらによって以下のデータが入っているとします。

[{'pk': 1, 'title': 'A', 'text': 'text1', 'number': 10},
 {'pk': 2, 'title': 'A', 'text': 'text2', 'number': 20},
 {'pk': 3, 'title': 'B', 'text': 'text3', 'number': 30}]

では、ここから対話モード(インタラクティブモード)で確認します。

コマンドプロント、もしくはターミナルで以下のコードを打ちます。

python manage.py shell

これで対話モードに移り変わります。

対話モードになったら、models.pyをインポートし、本題のfilterを使っていきます。

from models import Sample

output = Sample.objects.filter(text='text1')
print(output)
>>> <QuerySet [<Sample: A, text1, 10>]>

これがfilterの使い方となります。そんなに難しいことないですね。

公式サイトではこのページの一部が該当します。説明箇所は非常に短いです。

Django
The web framework for perfectionists with deadlines.

ここからAND検索やOR検索での使い方を見てみます。

filterのAND検索

AND検索は複数の条件で検索して検索結果をより狭くとりたい場合に便利です。

数学で言うとここでの検索結果は積集合になります。

では、実際にfilterを用いてAND検索を行ってみます。

output_and = Sample.objects.filter(text = 'text1' , title = 'A')
print(output_and)
>>> <QuerySet [<Sample: A, text1, 10>]>

これがAND検索になります。

filterの中でカンマで検索したい条件を区切ります。この場合だと2つの条件ですが、カンマで区切れば3以上の条件もできます。

filterのOR検索

OR検索は複数の条件で検索し、一つでも当てはまるものを出力します。つまり、検索結果をより広くとりたい場合に便利です。

数学で言うとここでの検索結果は和集合になります。

では、実際にfilterを用いてOR検索を行ってみます。

OR検索を行う際はQメゾットが必要になります。そのため、先にインポートします。

from django.db.models import Q

output_or = Sample.objects.filter(Q(title = 'title1')|Q(title = 'title2'))
print(output_or)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

これがOR検索になります。

filterの中でQメゾットをつけて括弧で括り、「|(バーティカルバー)」で検索したい条件を区切ります。

この場合もAND検索と同様で、Qメゾット内でバーティカルバーで区切れば3以上の条件でOR検索もできます。

filterで部分一致の出力

次にfilterで部分一致したものを出力したいとします。

部分一致したい場合はfilterの中の書き方を「(キーの名前)__contains='(条件)’」にして、抽出します。

実際に使う場合は以下の形になります。

output_contains = Sample.objects.filter(text__contains = 'text')
print(output_contains)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

これで該当するデータ全てが出てきます。この場合は全てのデータですね。

このようにしてfilterの条件で部分一致する結果を出力できます。

ちなみにこの部分一致もAND検索、OR検索ができます。

filterでの以上、以下の抽出方法

ここからfilterを用いてある数値以上、以下で抽出する方法を解説します。

特定の数値より大きいor以上の場合

ある特定の数値より大きい場合や以上を取りたい場合は以下のような書き方をします。

Model.objects.filter(field__gt='value') #大きい場合

model.objects.filter(field__gte='value') #以上の場合

実際は’value’の値に数字を入れることが多いです。そのため、上記例文を今回のサンプルモデルに適用させると

output_gt=Sample.objects.filter(number__gt='10')
print(output_gt)
>>> <QuerySet [<Sample: A, text2, 20>, <Sample: B, text3, 30>]>

output_gte=Sample.objects.filter(number__gte='10')
print(output_gte)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

‘gt’と’gte’で出力結果が異なります。

これはgtがGreater Than(より大きい)であり、特定の数値を含みません。

反対にgteはGreater Than or Equal to(より大きい、もしくは同等)であり、特定の数値を含みます。

この違いは注意しましょう。

特定の数値未満or以下の場合

ある特定の数値未満の場合や以下を取りたい場合は以下のような書き方をします。

Model.objects.filter(field__lt='value') #未満の場合

model.objects.filter(field__lte='value') #以下の場合

こちらも上記例文を今回のサンプルモデルに適用させてみると

output_lt=Sample.objects.filter(number__lt='30')
print(output_lt)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>]>

output_lte=Sample.objects.filter(number__lte='30')
print(output_lte)
>>><QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

こちらも’lt’と’lte’で出力結果が異なります。

これはltがLess Than(未満)であり、特定の数値を含みません。

反対にlteはLess Than or Equal to(未満、もしくは同等)であり、特定の数値を含みます。

filterの大文字小文字の完全一致、前方一致、後方一致

filterの中の条件はさまざまな形を取れます。

それが大文字小文字を含めた完全一致や前方一致、後方一致です。

大文字小文字を含めた完全一致

大文字小文字を含めた完全一致に関して例文を記載します。書き方は簡単です。

本記事で最初に紹介したコードも大文字小文字を含めた完全一致ですが、もう一つあります。

filterの中にfieldにアンダーバーを2つとexactをつける方法です。これで完全一致になります。

Model.objects.filter(field='value')
Model.objects.filter(field__exact='value')

サンプルのモデルで例文を書きます。

例文では2つとも完全一致のため、同じ出力になります。

output=Sample.objects.filter(text='text1')
print(output)
>>> <QuerySet [<Sample: A, text1, 10>]>

output_exact=Sample objects.filter(text__exact='text1')
print(output_exact)
>>> <QuerySet [<Sample: A, text1, 10>]>

これが大文字小文字を含めた完全一致です。また、大文字小文字を区別せずに一致するものを出力する場合は以下のコードを書きます。

output_iexact=Sample.objects.filter(text__iexact='TEXT1')
print(output_iexact)
>>> <QuerySet [<Sample: A, text1, 10>]>

また、前例で紹介した部分一致に関しても大文字小文字を含んだ完全一致が使えます。

output_contains = Sample.objects.filter(text__contains = 'text')
print(output_contains)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

また、大文字小文字を区別せずに出力する場合は先ほどと同様にcontainの前にiをつける方法です。

output_icontains = Sample.objects.filter(text__icontains = 'TEXT')
print(output_icontains)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

前方一致

次に前方一致の場合です。

これは部分一致に似てますが、条件に当てはまるか確認する部分は先頭からだけです。

部分一致は最初からでも途中からでも抽出しますが、前方一致は最初からのみです。

書き方はこれも比較的簡単です。filter内部のfieldの取り方が特徴的なだけです。

Model.objects.filter(field__startswith='value')

サンプルコードを書きます。

output_startswith=Sample.objects.filter(text__startswith='text')
print(output_startswith)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

また、大文字小文字の区別をせずに抽出したいのであれば、startswithの代わりにistartswithを使います。

後方一致

次に後方一致です。

これは前方一致とは反対に、条件にあうか確認する部分は最後からとります。

前方一致はstartswithでしたが、後方一致は

Model.objects.filter(field__endswith='value')

となります。

簡単なサンプルを下記に記載します。

output_endswith=Sample.objects.filter(text__endswith='t2')
print(output_endswith)
>>> <QuerySet [<Sample: A, text2, 20>]>

また、こちらも大文字小文字の区別をせずに抽出したいのであれば、endswithの代わりにiendswithを使います。

filterによるin抽出、range抽出

filterによる抽出方法は一つの文字列だけではありません。

inを使うことでリストやタプルも抽出条件にすることができます。

一例を挙げてみます。

output_in1=Sample.objects.filter(pk__in=[1, 2])
print(output_in1)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>]>

output_in2=Sample.objects.filter(pk__in=(1, 3))
print(output_in2)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: B, text3, 30>]>

また、filterによる範囲抽出も可能です。

範囲抽出にはrangeを使用します。

日付に使用されるのが一般的ですが、数値に関しても使用することができます。

Model.objects.filter(field__range=(start, end))

の形を取ります。

filter内部にはfield__rangeと(start, end)が必要になります。

output_range=Sample.objects.filter(pk__range=(1, 3))
print(output_range)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

filterによる正規表現での抽出

filterによる正規表現の抽出方法を紹介します。

これはpythonの正規表現を利用するため、reモジュールが必要になります。

正規表現に関する詳細は以下の記事で紹介しています。

では、実際の例文を書いていきます。

小文字大文字を区別する場合はregexのまま、区別しない場合はiregexを使います。

import re

output_regex=Sample.objects.filter(text__regex=r'.{4}\d')
print(output_regex)
>>> <QuerySet [<Sample: A, text1, 10>, <Sample: A, text2, 20>, <Sample: B, text3, 30>]>

filterとgetの違いは?

モデルデータから条件にあったデータを抽出する際にfilter以外にgetもあります。

しかし、この2つのfilterとgetは用途は似ていても、なにが違うかを具体的には分かりにくい部分があります。

では、filterとgetの違いを紹介しつつ、実際に使って違いを明確にしていきます。

出力の形式

それぞれ出力の形式が異なります。

getで出力すると、それぞれの値としてが出力します。

一方、filterは今まで見てきた通りQuerySet型として出力します。このQuerySet型はdjango特有の型になるため、少し曲者です。

output_get=Sample.objects.get(pk=1)
print(output_get)
>>> A, text1, 10

output_filter=Sample.objects.filter(pk=1)
print(output_filter)
>>> <QuerySet [<Sample: A, text1, 10>]>

空の出力の違い

続いては空の出力の違いです。それぞれにあるはずのないデータ(空のデータ)を出力してみます。

getでの空の出力はDoesNotExistエラーになります。

filterでは空のQuerySetが出力されます。これはエラーにはならないため、getとは少し異なります。

output_get=Sample.objects.get(pk=10)
print(output_get)
>>> models.Sample.DoesNotExist: Sample matching query does not exist.

output_filter=Sample.objects.filter(pk=1)
print(output_filter)
>>> <QuerySet []>

出力オブジェクトの中の値の取得

次に出力された結果をさらに絞ってみれるか確認してみましょう。

getでは出力されたオブジェクトの中からさらに細かな値をObjects.keyの形で出力できます。

filterでは出力形式がQuerySetになるため、出力された値の中の値は取得できずエラーになります。

output_get=Sample.objects.get(pk=1)
print(output_get.number)
>>> 10

output_filter=Sample.objects.filter(pk=1)
print(output_filter.number)
>>> AttributeError: 'QuerySet' object has no attribute 'number'

まとめ

基本的なfilterの使い方からAND検索、OR検索から始まり、getとの違い関して説明していきました。

だらだらと長い文章になってしまいましたが、filterの使い方で困っている方の助けになれば幸いです。

タイトルとURLをコピーしました