はじめに
公式ページの一番簡単な例を参考に django-filter が動くまでを初心者向けに報告したいと思います。内容は大きく二つです。
- 関数ビューでの作り方
- クラスビューでの作り方
この(その2)では、後者のクラスビューでの作り方を紹介します。
なお、django-filter のインストールやモデル作成は
django-filter の使い方(その1、関数ビュー編)
と同じです。そちらをご覧ください。
そして、関数ビューの作り方とごっちゃになりそうな方(私もでした)はプロジェクトを分けた方がよいかもしれません・・。
ちなみに私の環境ですが、
- python 3.8.6
- django 4.1.7
- django-filter 23.1
公式ページ
https://django-filter.readthedocs.io/en/stable/
前置きはこのくらいにしてルーティングから始めます。
ルーティング(クラスビュー)
myapp内に urls.py を作成して以下を記述します。
from django.urls import path
from . import views
from myapp.models import Product
urlpatterns = [
path("", views.FilterView.as_view(model=Product), name="product_list"),
]
通常のクラスビューと同じく as_view()を使用します。ここでの FilterView ですが、ListView を継承する形にしています。また、as_view()の引数には フィルターで使用するモデル(ここでは Product)を指定するように、と公式ページに書かれていました。
※公式ページに、from django_filters.views import FilterView とありましたが、これではうまくいきませんでした。
プロジェクトの urls.py も変更しておきます。これは関数ビューと同じです。
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('myapp.urls')),
]
フィルター定義ファイル(filters.py)の作成
次に、myapp 内に、filters.py の別ファイルを作ります。
このファイルも関数ビューと同じです。
import django_filters
from .models import Product
class ProductFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='iexact')
class Meta:
model = Product
fields = ['price', 'release_date']
クラスビュー(views.py)の定義
views.py に製品一覧(product_list)を表示するためのクラスビューを定義します。
from django.views.generic import ListView
from .filters import ProductFilter
class FilterView(ListView):
template_name = 'product_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["filter"] = ProductFilter(self.request.GET,
queryset=self.get_queryset())
return context
当然ですが、関数ビューと大きく異なります。FilterViewは、ListViewを継承します。また、get_context_data()関数によって、検索キーワードのパラメータを受け取り、ProductFilter によって context内の"filter"をオーバーライドします。
そして・・・データを絞り込む filter( ) メソッドはどこにも出てきません!
※ここで、from django_filters.views import FilterView として、FilterViewを継承する形をとってみましたが、うまく行きませんでした。
テンプレートファイル(product_list.html)の作成
myapp内に templates/myapp とディレクトリーを作って、product_list.html を作成します。関数ビューと同じ内容です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>製品一覧</title>
</head>
<body>
<form method="get">
{% csrf_token %}
{{ filter.form.as_p }}
<input type="submit" />
</form>
{% for obj in filter.qs %}
{{ obj.name }} - ${{ obj.price }} {{ obj.release_date }}<br />
{% endfor %}
</html>
そして、いつものように、
python manage.py runserver
を動かして、http://127.0.0.1:8000/にアクセスすると
検索フォーム付きで製品一覧が表示できました。パチパチパチ!
検索もバッチリですね。
最後に
関数ビューとクラスビューに分けて、django-filter の使い方を見てきました。
私が django-filter による検索機能の実装がなかなかできなかった理由が、
- 通常のforms.py や objects.filter を使う方法と混同する
- django-filter の中でも関数ビューの実装とクラスビューの実装と混同する
- 基本を理解せず、いきなりDBから動的に取得する choisefield に挑戦して撃沈
といった所にありました。Django フレームワーク全般がそうですが、初心者が少し道を外れるとエラー地獄になって挫折しまいます。ただ、これは大きな道筋を押さえていないからだ、と思っています。
この記事が「検索機能の実装は苦手で面倒だな」と思っている方に少しでもお役に立てればと思います。プログラムも小さな成功体験からですから。
また、不備を指摘して頂けると助かります。まだまだ私も python初心者なので。