前回、todolistをdjangoで作成する記事を挙げたのですが、記事を上げた時点で新しいタスクが投稿できないバグに直面しました。エラー文を見てもよくわからず、とても困りましたがformの書き方に問題がありました。
models.py
from django.db import models
from django.urls import reverse
#カテゴリモデル
class Category(models.Model):
#カテゴリ名
name = models.CharField(max_length=255)
#カテゴリを設定した人
author = models.ForeignKey(
'auth.User',on_delete=models.CASCADE,
)
#作成日
created_at = models.DateTimeField(auto_now_add=True)
#更新日
updated_at = models.DateTimeField(auto_now=True)
#これ入れないと管理画面でcategoryobjectって名前になる
def __str__(self):
return self.name
class Task(models.Model):
#タスク名
title = models.CharField(max_length=255)
# タスクを設定した人
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
#カテゴリ(外部キー参照)
category = models.ForeignKey(
Category, on_delete=models.PROTECT
)
#完了確認
completed = models.BooleanField(default=False)
#締切日
deadline = models.DateTimeField()
#タスク作成日
created_at = models.DateTimeField(auto_now_add=True)
#タスク完了日
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('todo:detail', kwargs={'pk': self.pk})
モデルはこのようになっていて、タスクの設定者をauth.user
を外部キーとして、選択できるようになっていました。
しかし、forms.py
は
forms.py
from django import forms
from django.contrib.admin.widgets import AdminDateWidget
from .models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = ['title', 'author', 'category', 'deadline', ]
#ウィジェットはフォームとかの部品の種類を指定する要素
#djangoのフォームウィジェットにHTML属性を付与する(attrs)
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'author': forms.TextInput(attrs={'class': 'form-control'}),
'category': forms.Select(attrs={'class': 'form-control'}), # カテゴリが選択肢の場合
'deadline': forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-control'}),
}
'author': forms.TextInput(attrs={'class': 'form-control'}),
となっており、コレが原因で投稿できなくなっていました。
これを以下のようにforms.Select
使うことで改善しました。
forms.py
from django import forms
from django.contrib.admin.widgets import AdminDateWidget
from .models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = ['title', 'author', 'category', 'deadline', ]
#ウィジェットはフォームとかの部品の種類を指定する要素
#djangoのフォームウィジェットにHTML属性を付与する(attrs)
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'author': forms.Select(attrs={'class': 'form-control'}),#修正
'category': forms.Select(attrs={'class': 'form-control'}), # カテゴリが選択肢の場合
'deadline': forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-control'}),
}
forms.Select
で選択肢が準備されるのは、Metaクラスとして定義した際にデータベースから情報を参照して、以下のようなコードを内部的に実行しているかららしいです。
author = forms.ModelChoiceField(queryset=User.objects.all())
コレに気づいたのは管理者画面でtask
を設定しようとしたら、セレクターになっていたのでそれで気づきました。
もし困った方がいたら、トラブルシューティンングで活用してください。