【日報アプリ開発】django-filterの実例!年月別 下書き/公開済 のフィルターを作ろう!

Django

(最終更新月:2021年7月)

日報アプリを作成しています

django-filterを使って、「年月別のフィルターを作りたい!」と思ったのですが特に方法が書いてあるページが見当たらない!

そもそも備え付けのフィルターで事足りるからだと思いますが、django-filterで他の機能も追加していく予定なので、このままdjango-filterで作ることにしました

今回の記事では、

  • 保存しているデータのdatetimeフィールドから年と月を抽出し、リスト化
  • 作成したリストをフィルターへ渡す
  • 選択した値によってリストで表示されるクエリセットを変更するメソッドを作る

という方法の解説となります

そもそも「django-filterを使ったことがない!」という方はdjango-filterの導入から各ファイルの設定までを解説したこちらの記事をご覧ください

【コード全体】filter.py

下記にて、各パートについて解説をしますが、最終的にはこんな感じになりました

import django_filters
from .models import NippoModel
from distutils.util import strtobool

qs = NippoModel.objects.all()
choice_option = [(obj.timestamp.year, obj.timestamp.month) for obj in qs]
choice_option = list(set(choice_option))

DATE_OPTIONS = [((year, month), f"{year}年{month}月") for year, month in choice_option]
DATE_OPTIONS.insert(0, (None, "---"))

class NippoModelFilter(django_filters.FilterSet):
    public = django_filters.BooleanFilter(label="公開")
    timestamp = django_filters.TypedChoiceFilter(choices=DATE_OPTIONS,method="timestamp_checker", label="公開月")
    class Meta:
        model = NippoModel
        fields = ["public", "timestamp"]

    def timestamp_checker(self, queryset, name, value):
        if value is not None:
            year, month = eval(value)
            return queryset.filter(timestamp__year=year).filter(timestamp__month=month)
        else:
            return queryset

「よくわからない!」という方に向けて、次章よりパートごとの解説をしていきます

※publicについて、BooleanFilterを設定してますが、当記事で解説は省きます

詳しくは、公式ドキュメントなどご覧ください

モデルのフィールドについては、こちらで解説しています↓(publicは後から追加しました)

保存しているデータの年月を抽出、リスト化

qs = NippoModel.objects.all()
choice_option = [(obj.timestamp.year, obj.timestamp.month) for obj in qs]
choice_option = list(set(choice_option))
解説
  • モデルから全データを取り出します
  • 内包表記を使い、(年, 月)のタプルで構成されたリストを作成します
  • 重複しているデータを削除するために、set()を使っています

※「内包表記って何?」という方はこちら↓の記事をご覧ください!

今回のリストはこんなものになっています

choice_option = [(2021, 5), (2021, 6), ...]

フィルターへ渡す用のリストを作成

前章で作ったリストを、フィルターのchoces引数へ渡すために変更します

通常のリストを

[(受け取る値, テンプレートで表示される文字列), ...」

となるよう変更します

DATE_OPTIONS = [((year, month), f"{year}年{month}月") for year, month in choice_option]
DATE_OPTIONS.insert(0, (None, "---"))
解説
  • 前章で作ったリストを使い、適切な形へ変更
  • 「何も選択しない」というoptionを作成し追加

filterクラスの作成

ベースとなるクラスの作成方法についてはこちらの記事をご覧ください↓

対象の部分を抜粋すると、

class NippoModelFilter(django_filters.FilterSet):
    ...
    timestamp = django_filters.TypedChoiceFilter(choices=DATE_OPTIONS,method="timestamp_checker", label="公開月")
    
    ...

    def timestamp_checker(self, queryset, name, value):
        if value is not None:
            year, month = eval(value)
            return queryset.filter(timestamp__year=year).filter(timestamp__month=month)
        else:
            return queryset
解説
  • TypedChoiceFilterフィールドを使います
  • choicesには前章で作成した「DATE_OPTIONS」を渡します
  • クラス内で作成したメソッドを文字列で指定します
  • メソッド「timestamp_checker」では受け取る値により、filterされたクエリセットを返します

まとめ

django-filterで年月別リスト表示をするために、

  • 保存したデータの年月を取り出す
  • 取り出した年月をリスト化し、フィルターに渡す
  • メソッドを使い受け取った値で適切なクエリセットを返す

方法を解説しました

前章までのコードをコピペなどを使い、皆様のWebアプリ制作の一助になれたら幸いです

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