はじめに
公式ページの一番簡単な例を参考にdjango-filterが動くまでを初心者向けに報告したいと思います。記事は大きく二つです。
・関数ビューでの作り方
・クラスビューでの作り方
以下のことには触れません。
・Django REST Framework との統合
・ModelChoiceFilter を使っての例(プルダウン式での選択検索)
初心者にとってこれらは応用で難しいので、ここでは基本的な動きを理解することに徹します。
当方の環境ですが
- python 3.8.6
- django 4.1.7
- django-filter 23.1
django-filterの公式ページ
https://django-filter.readthedocs.io/en/stable/
インストール
すでにプロジェクトやアプリ作成(ここでは'myapp'とします)まで完了している前提で進めます。仮想環境に入って
pip install Django-filter
ここの真ん中はハイフンです。
settings.py に、'django_filters',を追加します。
INSTALLED_APPS = [
...
'django_filters',
...
]
こちらはアンダーバー、sが付きます。
モデル作成(models.py)
models.py に公式のものと同じモデル(ProductとManufacturer)を作成します。
from django.db import models
class Manufacturer(models.Model):
name = models.CharField(max_length=20)
country = models.CharField(max_length=20)
class Meta:
db_table = 'manufacturer'
def __str__(self) :
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=5, decimal_places=2)
description = models.TextField()
release_date = models.DateField()
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
class Meta:
db_table = 'product'
def __str__(self) :
return self.name
Product の manufacturerは外部キーです。
そして、いつものように、
python manane.py makemigrations
python manane.py migrate
を実行。スーパーユーザーで管理画面にログインして何件がデータを登録しておきましょう。
ルーティング(関数ビュー)
myapp内に urls.py を作成して以下を記述します。
from django.urls import path
from . import views
urlpatterns = [
path("", views.product_list, name="product_list"),
]
忘れずに、プロジェクトの 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 という別ファイルを作ります。
ここで初めて、django_filters をインポートしてProduct モデルに対するフィルター仕様を定義します。例は、公式ページの一番最初のものにします。
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']
FormViewと同じような感じです。
少し解説すると、
・モデルと同じフィールド名を指定する。
・CharFilter : キャラクター型のフィルター。他に、NumberFilter, DateFilter, BooleanFilter, ChoiceFilter ・・などなど。
・ルックアップ式(lookup_expr)が使える。
ここでの'iexact'は正確に一字一句同じキーワードで絞るという指定になります。他に'icontains'(を含む),'gt'(<),'lt'(>)とか。この辺は公式をご覧ください。
そして、ここで定義した、name, price, release_date の3つのfield がフィルターの対象になります。なお、Meta クラスの fields に指定した分(nameのように明示的に定義していない分)については、'iexact'の扱いになります。
※別ファイルとしましたが、上記の内容はviews.py に直接書いても構いません。
関数ビュー(views.py)の定義
views.py に製品一覧(product_list)を表示するための関数ビューを定義します。
from django.shortcuts import render
from .models import Product
from .filters import ProductFilter
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render(request, 'myapp/product_list.html', {'filter': f})
前項の filters.py で作成した ProductFilter も import して使ってください。
ここまでで、あれ・・と思われた方は鋭いです。 検索に関するフォーム(forms.py)の importや記述がありません。django-filter では、先ほど定義した name, price, release_date の3つの field をもつ検索フォームのオブジェクトまで生成してくれます。
※f の中身が見たくて、print(f)を入れたのですがなぜかエラーになります。
テンプレートファイル(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>
ここで、views.py の render 第3引数で渡された辞書型の filter オブジェクトの各項目を表示させていきます。なお、 filter.form
とか filter.qs
(網掛け部分)は予約語なので、filter.searchform とか filter.queryset とかにしたらダメです。
そして、検索 form 部分の表示ですが、個別に表示させたい場合は、as_p を使用せず、
{{ filter.form.name.label }} {{ filter.form.name }}
という形にすれば自由にレイアウトできます。
おわりに
そして、いつものように、
python manage.py runserver
を動かして、http://127.0.0.1:8000/にアクセスすると
検索フォーム付きで製品一覧が表示できました。パチパチ!
ちゃんと絞り込みもできますね。
これで基本が押さえられたと思います。
次に(その2)では、クラスビューの場合を報告したいと思います。
django-filter の使い方(その2、クラスビュー編)