0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

django-filter の使い方(その2、クラスビュー編)

Last updated at Posted at 2023-03-29

はじめに

公式ページの一番簡単な例を参考に 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 を作成して以下を記述します。

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 も変更しておきます。これは関数ビューと同じです。

[project]/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 の別ファイルを作ります。
このファイルも関数ビューと同じです。

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)を表示するためのクラスビューを定義します。

myapp/views.py
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 を作成します。関数ビューと同じ内容です。

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-filter1.jpg
検索フォーム付きで製品一覧が表示できました。パチパチパチ!
django-filter3.jpg
検索もバッチリですね。

最後に

 関数ビューとクラスビューに分けて、django-filter の使い方を見てきました。
私が django-filter による検索機能の実装がなかなかできなかった理由が、

  • 通常のforms.py や objects.filter を使う方法と混同する
  • django-filter の中でも関数ビューの実装とクラスビューの実装と混同する
  • 基本を理解せず、いきなりDBから動的に取得する choisefield に挑戦して撃沈

といった所にありました。Django フレームワーク全般がそうですが、初心者が少し道を外れるとエラー地獄になって挫折しまいます。ただ、これは大きな道筋を押さえていないからだ、と思っています。
 この記事が「検索機能の実装は苦手で面倒だな」と思っている方に少しでもお役に立てればと思います。プログラムも小さな成功体験からですから。
また、不備を指摘して頂けると助かります。まだまだ私も python初心者なので。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?