[Django] ModelChoiceFieldで選択肢をフィルタリングする方法

記事内に広告が含まれています。

ModelChoiceFieldはデータベースに格納されている値を選択させるために用いられるメソッドです。

本記事では、データベースの値全てを選択肢に表示するのではなく、一部の値のみを表示させる設定方法について解説します。

この機能により、ログインしているユーザに関する情報のみ表示・選択できるように設定できます。

解説したいこと

idownernamebookname
1山田pythonの本
2山田htmlの本
3田中cssの本
テストのための本管理データベース

例えばこのようなデータベースがあった際、山田がownerの本だけを選択肢として表示する(↓の画像)方法を解説します。

こんな画面を表示する方法を解説

結論

views.pyとforms.pyの2つを以下のように変更します。

  • forms.py: queryset属性に空の選択肢を用意する
  • views.py: 空のquerysetにフィルタリングした結果を追加する
#forms.py
class testForm(forms.Form):
    col = forms.ModelChoiceField(
        queryset=データベース名.objects.none(), #空のクエリセット
        widget=forms.widgets.Select
    )

views.py

form = testForm()
form.fields['col'].queryset = データベース名.objects.filter(フィルタ条件)

views.pyで制限をかけるので、ログインユーザだけの選択肢など柔軟にフィルタリングすることができます。

デモンストレーション

解説したいこと で述べた画面を表示する方法をデモンストレーションします。

前提

templates/index.html を用いてブラウザの画面に文字を表示できるような状態を前提とします。

私の過去の記事でも紹介しているので、適宜参照ください。

手順1. データの準備

まず、以下のようなデータベースを作成します。

#models.py
from django.db import models

class Book(models.Model):
    ownername = models.CharField("所有者", max_lngth=30)
    bookname = models.CharField("本の名前", max_lngth=30)

    def __str__(self):
        return self.bookname

その後、マイグレーションします。

python manage.py makemigrations
python manage.py migrate

その後、django shellを起動してデータを入力します。

python manage.py shell
# appはアプリケーションフォルダの名前
>>> from app.models import Books
>>> b = Books(ownername="山田", bookname="pythonの本")
>>> b.save()
>>> b = Books(ownername="山田", bookname="htmlの本")
>>> b.save()
>>> b = Books(ownername="田中", bookname="cssの本")
>>> b.save()

手順2: forms.py, views.pyの追記

このデータベースから本の名前を抽出するフォームを用意します。

#forms.py
from django import forms
from .models import Books
class bookname_form(forms.Form):
    bookname = forms.ModelChoiceField(
        label="書籍名",
        queryset=Books.objects.none(),#空の選択肢
        widget=forms.widgets.Select,
        required=True,
    )

views.pyで空のクエリセットにログインユーザでフィルタリングした選択肢を追加します。

#views.py
from django.shortcuts import render
from .forms import bookname_form
from .models import Books

def index(request):
    ### 選択肢を山田だけに制限しているコード ###
    form = bookname_form()
    form.fields['bookname'].queryset = Books.objects.filter(ownername="山田")
    ### ここまで ####
    params = {
        "form": form,
    }
    return render(request, "index.html", params)

index.html (bodyタグのみ表示)

<body>
 <h2>選択肢のフィルタリングのデモンストレーション</h2>
 <form action="deleteBooking" method="POST">
    <!--POSTを行う際に必要 -->
    {% csrf_token %}
    <div>
      <label>{{ form.bookname.label }} {{ form.bookname }}</label>
      <input type="submit" value="送信">
    </div>
  </form>
</body>

以下のコマンドで表示されたURLにブラウザでアクセスすると

python manage.py runserver
デモしたい内容: 山田が所有者の本だけを選択肢に表示

山田が所有者となっていた2冊の本のみが選択できるようになり、田中が所有する “cssの本” は選択できなくなりました。

今回の方法のメリット: ログインユーザの情報だけ表示することが可能

フィルタリングの条件を request.user に設定すれば、ログインしているユーザの情報だけを表示させることができ、他のユーザの情報を閲覧・選択できなくすることが可能になります。

#views.pyの
form.fields['bookname'].queryset = Books.objects.filter(ownername=request.user)

まとめ

ModelChoiceField を使って、ログインしているユーザ名で表示内容をフィルタリングする方法について解説しました。

再度まで読んでいただき誠にありがとうございました。

コメント