やりたいこと
Modelに外部キー(FOREIGN KEY)制約のある2つのテーブルを用意したとき、Formではユーザー(ログインユーザー)に紐づいた、登録データを表示したいです。
クラスベースの汎用ビューを使ったときの、やり方でつまずいたので、記録しておきます。
例えば、以下のようなTodoリストを作成します。
このとき、1つのTodo Itemには選択できるCategoryが複数あります。
以下のように、ログインユーザーで登録しているCategoryが2つあるとします。
このとき(当然のことですが)、登録や編集のフォームで選択できるCategoryは、ログインユーザーが登録したCategoryのみとしたいです。
環境
Python 3.8.0
Django 3.0.4
Bootstrap 4.1.3
プラグイン:django-bootstrap-modal-forms
※一般的なCreateView、UpdateView等を使う場合も同様のやり方です
やり方
このページを参考にしました。
使用するModel
# mypeoject/myapp/models.py
import datetime
from django.db import models
class Category(models.Model):
category_name = models.CharField(max_length=20, unique=True)
user = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE
)
def __str__(self):
return self.category_name
class TodoItem(models.Model):
item = models.CharField(max_length=50)
item_date = models.DateField(default=datetime.date.today)
categories = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
user = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE
)
def __str__(self):
return self.item
上記の例の場合、使用するModelには、TodoItemテーブルと、外部キー(FOREIGN KEY)制約のあるCategoryテーブルの2つを用意しています。
forms.pyの編集
# mypeoject/myapp/forms.py
from bootstrap_modal_forms.forms import BSModalForm
from django import forms
from queryset_filtering_app.models import TodoItem, Category
class CreateUpdateTodoItemForm(BSModalForm):
class Meta:
model = TodoItem
fields = ['item', 'item_date', 'categories']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(CreateUpdateTodoItemForm, self).__init__(*args, **kwargs)
self.fields['categories'].queryset = Category.objects.filter(user=user)
class CreateCategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ["category_name"]
forms.pyは上記のように、def __init__()の記述を追加します。
views.pyの編集
# mypeoject/myapp/views.py
class CreateTodoItemFormView(BSModalCreateView):
template_name = 'template_name.html'
form_class = CreateUpdateTodoItemForm
success_message = 'Success: Item was created.'
success_url = reverse_lazy('redirect_name')
def get_form_kwargs(self):
kwargs = super(CreateTodoItemFormView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.instance.user_id = self.request.user.id
return super(CreateTodoItemFormView, self).form_valid(form)
class UpdateTodoItemFormView(BSModalUpdateView):
model = TodoItem
template_name = 'template_name.html'
form_class = CreateUpdateTodoItemForm
success_message = 'Success: Item was updated.'
success_url = reverse_lazy('redirect_name')
def get_form_kwargs(self):
kwargs = super(UpdateTodoItemFormView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
views.pyでは上記のように、def get_form_kwargs()の記述を追加します。
CreateViewのdef form_valid()の箇所は、登録時にログインユーザーをuserに登録するためのコードです。
おわりに
登録・編集フォームでユーザーに紐づく登録データを表示する方法を記載しました。
基本的なところだと思いますが、私のような初心者だと、適切な記事を見つけられず、すぐには解決できないこともあるかと思うので、参考にしていただければと思います。