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 の使い方(その1、関数ビュー編)

Last updated at Posted at 2023-03-29

はじめに

公式ページの一番簡単な例を参考に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',を追加します。

[project]/settings.py
INSTALLED_APPS = [
    ...
    'django_filters',
    ...
]

こちらはアンダーバー、sが付きます。

モデル作成(models.py)

models.py に公式のものと同じモデル(ProductとManufacturer)を作成します。

myapp/models.py
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 を作成して以下を記述します。

myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.product_list, name="product_list"),
]

忘れずに、プロジェクトの 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 という別ファイルを作ります。
ここで初めて、django_filters をインポートしてProduct モデルに対するフィルター仕様を定義します。例は、公式ページの一番最初のものにします。

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']

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

myapp/views.py
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 を作成します。

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/にアクセスすると
django-filter1.jpg
検索フォーム付きで製品一覧が表示できました。パチパチ!
django-filter2.jpg
ちゃんと絞り込みもできますね。

これで基本が押さえられたと思います。
次に(その2)では、クラスビューの場合を報告したいと思います。
django-filter の使い方(その2、クラスビュー編)

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?