Django 1つのmodelを複数formから保存
解決したいこと
プログラミング初心者です。
Djangoで問題集(長文問題に各小問題が複数ある)のようなWebアプリを作成しています。
forms.pyのformの複数のfieldを、ある程度固めてCSSで折り畳んだ状態からクリックで表示されるようにする為に、formの段階で複数に分け、入力値を1つのmodelに保存させたく思っています。
必要項目をformに入力後、「作成する」ボタンを押した時点でエラーになりうまくいきません。
views.pyのCreateViewが間違っていると思うのですが。
どなたか解決方法をお教えていただけますでしょうか。
よろしくお願いいたします。
発生している問題・エラー
django.db.utils.IntegrityError: NOT NULL constraint failed: book_question2.user_id
該当するソースコード
class CreateQuestionView2(LoginRequiredMixin, CreateView):
template_name = 'book/question_create2.html'
form_class = QuestionForm2
form_classA = QuestionForm2A
form_classB = QuestionForm2B
form_classC = QuestionForm2C
form_classD = QuestionForm2D
form_classE = QuestionForm2E
form_classF = QuestionForm2F
form_classG = QuestionForm2G
form_classH = QuestionForm2H
form_classI = QuestionForm2I
form_classJ = QuestionForm2J
form_classLast = QuestionForm2last
success_url = reverse_lazy('create-question2')
def get_context_data(self, **kwargs):
user = self.request.user
context = CreateView.get_context_data(self, **kwargs)
form1 = self.form_classA(self.request.POST or None)
form2 = self.form_classB(self.request.POST or None)
form3 = self.form_classC(self.request.POST or None)
form4 = self.form_classD(self.request.POST or None)
form5 = self.form_classE(self.request.POST or None)
form6 = self.form_classF(self.request.POST or None)
form7 = self.form_classG(self.request.POST or None)
form8 = self.form_classH(self.request.POST or None)
form9 = self.form_classI(self.request.POST or None)
form10 = self.form_classJ(self.request.POST or None)
formLast = self.form_classLast(self.request.POST or None)
context.update({'form1':form1})
context.update({'form2':form2})
context.update({'form3':form3})
context.update({'form4':form4})
context.update({'form5':form5})
context.update({'form6':form6})
context.update({'form7':form7})
context.update({'form8':form8})
context.update({'form9':form9})
context.update({'form10':form10})
context.update({'formLast':formLast})
return context
urlpatterns = [
path('question2/create/', views.CreateQuestionView2.as_view(), name='create-question2')
]
↓QuestionForm2とQuestion2Aのみ表示させてますが、QuestionForm2B〜QuestionForm2JとQuestionForm2Lastもあります。
class QuestionForm2(ModelForm):
class Meta:
model = Question2
fields = ['questionBig', 'thumbnailBig1', 'thumbnailBig2', 'thumbnailBig3', 'thumbnailBig4', 'thumbnailBig5']
widgets = {
'questionBig': forms.Textarea(attrs={'rows':5, 'cols':60}),
}
class QuestionForm2A(ModelForm):
class Meta:
model = Question2
fields = ['questionSmall1','thumbnailQ1Small1', 'thumbnailQ2Small1', 'thumbnailQ3Small1', 'answerSmall1','wronganswer1Small1','wronganswer2Small1','wronganswer3Small1','wronganswer4Small1','wronganswer5Small1','wronganswer6Small1','wronganswer7Small1','wronganswer8Small1','wronganswer9Small1','hint1Small1','hint2Small1','explanationSmall1', 'thumbnailA1Small1', 'thumbnailA2Small1', 'thumbnailA3Small1']
widgets = {
'questionSmall1': forms.Textarea(attrs={'rows':3, 'cols':45}),
'answerSmall1': forms.Textarea(attrs={'rows':1, 'cols':45}),
'wronganswer1Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer2Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer3Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer4Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer5Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer6Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer7Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer8Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'wronganswer9Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'explanationSmall1': forms.Textarea(attrs={'rows':1, 'cols':45}),
'hint1Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
'hint2Small1': forms.Textarea(attrs={'rows':1, 'cols':43}),
}
↓このように折り畳んだ問題が第10問まであり一番下に「作成する」ボタンがあります。
class Question2(models.Model):
questionBig = models.TextField(verbose_name="問題(大)")
thumbnailBig1 = models.ImageField(verbose_name="画像1 (問題大)", null=True, blank= True)
thumbnailBig2 = models.ImageField(verbose_name="画像2 (問題大)", null=True, blank= True)
thumbnailBig3 = models.ImageField(verbose_name="画像3 (問題大)", null=True, blank= True)
thumbnailBig4 = models.ImageField(verbose_name="画像4 (問題大)", null=True, blank= True)
thumbnailBig5 = models.ImageField(verbose_name="画像5 (問題大)", null=True, blank= True)
questionSmall1 = models.TextField(verbose_name="問題1")
thumbnailQ1Small1 = models.ImageField(verbose_name="画像1 (問題)", null=True, blank= True)
thumbnailQ2Small1 = models.ImageField(verbose_name="画像2 (問題)", null=True, blank= True)
thumbnailQ3Small1 = models.ImageField(verbose_name="画像3 (問題)", null=True, blank= True)
answerSmall1 = models.TextField(verbose_name="正解")
wronganswer1Small1= models.TextField(verbose_name="誤回答1")
wronganswer2Small1 = models.TextField(verbose_name="誤回答2")
wronganswer3Small1 = models.TextField(verbose_name="誤回答3")
wronganswer4Small1 = models.TextField(verbose_name="誤回答4", null=True, blank= True)
wronganswer5Small1 = models.TextField(verbose_name="誤回答5", null=True, blank= True)
wronganswer6Small1 = models.TextField(verbose_name="誤回答6", null=True, blank= True)
wronganswer7Small1 = models.TextField(verbose_name="誤回答7", null=True, blank= True)
wronganswer8Small1 = models.TextField(verbose_name="誤回答8", null=True, blank= True)
wronganswer9Small1 = models.TextField(verbose_name="誤回答9", null=True, blank= True)
explanationSmall1 = models.TextField(verbose_name="解説", null=True, blank=True,)
thumbnailA1Small1 = models.ImageField(verbose_name="画像1 (正解)", null=True, blank= True)
thumbnailA2Small1 = models.ImageField(verbose_name="画像2 (正解)", null=True, blank= True)
thumbnailA3Small1 = models.ImageField(verbose_name="画像3 (正解)", null=True, blank= True)
hint1Small1 = models.TextField(verbose_name="ヒント1", null=True, blank=True,)
hint2Small1 = models.TextField(verbose_name="ヒント2", null=True, blank=True,)
questionSmall2 = models.TextField(verbose_name="問題2")
thumbnailQ1Small2 = models.ImageField(verbose_name="画像1 (問題)", null=True, blank= True)
thumbnailQ2Small2 = models.ImageField(verbose_name="画像2 (問題)", null=True, blank= True)
thumbnailQ3Small2 = models.ImageField(verbose_name="画像3 (問題)", null=True, blank= True)
answerSmall2 = models.TextField(verbose_name="正解")
wronganswer1Small2 = models.TextField(verbose_name="誤回答1")
wronganswer2Small2 = models.TextField(verbose_name="誤回答2")
wronganswer3Small2 = models.TextField(verbose_name="誤回答3")
wronganswer4Small2 = models.TextField(verbose_name="誤回答4", null=True, blank= True)
wronganswer5Small2 = models.TextField(verbose_name="誤回答5", null=True, blank= True)
wronganswer6Small2 = models.TextField(verbose_name="誤回答6", null=True, blank= True)
wronganswer7Small2 = models.TextField(verbose_name="誤回答7", null=True, blank= True)
wronganswer8Small2 = models.TextField(verbose_name="誤回答8", null=True, blank= True)
wronganswer9Small2 = models.TextField(verbose_name="誤回答9", null=True, blank= True)
explanationSmall2 = models.TextField(verbose_name="解説", null=True, blank=True,)
thumbnailA1Small2 = models.ImageField(verbose_name="画像1 (正解)", null=True, blank= True)
thumbnailA2Small2 = models.ImageField(verbose_name="画像2 (正解)", null=True, blank= True)
thumbnailA3Small2 = models.ImageField(verbose_name="画像3 (正解)", null=True, blank= True)
hint1Small2 = models.TextField(verbose_name="ヒント1", null=True, blank=True,)
hint2Small2 = models.TextField(verbose_name="ヒント2", null=True, blank=True,)
#コードが長いため、「第3問目」〜「第9問目」を省略
questionSmall10 = models.TextField(verbose_name="問題10", null=True, blank= True)
thumbnailQ1Small10 = models.ImageField(verbose_name="画像1 (問題)", null=True, blank= True)
thumbnailQ2Small10 = models.ImageField(verbose_name="画像2 (問題)", null=True, blank= True)
thumbnailQ3Small10 = models.ImageField(verbose_name="画像3 (問題)", null=True, blank= True)
answerSmall10 = models.TextField(verbose_name="正解", null=True, blank= True)
wronganswer1Small10 = models.TextField(verbose_name="誤回答1", null=True, blank= True)
wronganswer2Small10 = models.TextField(verbose_name="誤回答2", null=True, blank= True)
wronganswer3Small10 = models.TextField(verbose_name="誤回答3", null=True, blank= True)
wronganswer4Small10 = models.TextField(verbose_name="誤回答4", null=True, blank= True)
wronganswer5Small10 = models.TextField(verbose_name="誤回答5", null=True, blank= True)
wronganswer6Small10 = models.TextField(verbose_name="誤回答6", null=True, blank= True)
wronganswer7Small10 = models.TextField(verbose_name="誤回答7", null=True, blank= True)
wronganswer8Small10 = models.TextField(verbose_name="誤回答8", null=True, blank= True)
wronganswer9Small10 = models.TextField(verbose_name="誤回答9", null=True, blank= True)
explanationSmall10 = models.TextField(verbose_name="解説", null=True, blank=True,)
thumbnailA1Small10 = models.ImageField(verbose_name="画像1 (正解)", null=True, blank= True)
thumbnailA2Small10 = models.ImageField(verbose_name="画像2 (正解)", null=True, blank= True)
thumbnailA3Small10 = models.ImageField(verbose_name="画像3 (正解)", null=True, blank= True)
hint1Small10 = models.TextField(verbose_name="ヒント1", null=True, blank=True,)
hint2Small10 = models.TextField(verbose_name="ヒント2", null=True, blank=True,)
category= models.CharField(
verbose_name="カテゴリ",
max_length=100,
choices = CATEGORY2
)
created_at = models.DateTimeField(auto_now_add=True)
shoseki= models.CharField(
verbose_name="書籍",
max_length=200,
null=True, blank=True,
choices = SHOSEKILIST
)
shoseki_page = models.CharField(verbose_name="書籍ページ", max_length=10, null=True, blank=True,)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
自分で試したこと
ネット記事を参考に、views.pyに下記関数を追加してみましたが、同様のエラーになりました。
#上記 「class CreateQuestionView2(LoginRequiredMixin, CreateView):」の下に追加
if form.is_valid():
with transaction.atomic():
create_user = request.user
form.save()
form1.save()
form2.save()
form3.save()
form4.save()
form5.save()
form6.save()
form7.save()
form8.save()
form9.save()
form10.save()
formLast.save()
else:
self.form_invalid(form)
return HttpResponseRedirect(self.get_success_url())