質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Q&A

解決済

1回答

2688閲覧

【Django】FormViewを継承したクラスの内部にget_context_data()を定義するとform.non_field_errorsが表示されない

Sora66

総合スコア18

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

0グッド

0クリップ

投稿2021/12/09 02:23

編集2021/12/09 07:57

前提・実現したいこと

フォームから受け取ったクエリの書式が有効かどうかforms.pyで判定し、無効である場合、

raise forms.ValidationError("13桁の半角数字を入力してください。")

を返し、index.htmlにエラーを表示させたいです。

{% for error in form.non_field_errors %} <div class="alert alert-danger"> {{ error }} </div> {% endfor %}

views.pyではフォームとモデルオブジェクトの両方をテンプレートに渡すために、FormViewを継承したクラスの内部に関数**form_valid()get_context_data()**を定義しています。

発生している問題

FormViewを継承したクラスの内部に**form_valid()get_context_data()**の両方を定義するとform.non_field_errorsが表示されません。
しかし、**form_valid()**のみを定義した場合、form.non_field_errorsが正しく表示されます。

おそらく**get_context_data()**が悪さをしていると思われますが、改善策がわかりません。

該当のソースコード

forms.py

Python

1from django import forms 2from django.core.exceptions import ValidationError 3 4import unicodedata 5 6from .models import RecordID 7from .scraping import isRightID 8 9class ContactForm(forms.Form): 10 record_id = forms.CharField(label="資料ID") 11 12 def clean(self): 13 cleaned_data = super().clean() 14 text = cleaned_data.get("record_id") 15 try: 16 if len(text) != 13 or isHalfNum(text) != True: 17 raise forms.ValidationError("13桁の半角数字を入力してください。") 18 except: 19 raise forms.ValidationError("13桁の半角数字を入力してください。") 20 return cleaned_data 21 22 def save(self): 23 data = self.cleaned_data 24 recordid = RecordID( 25 record_id = data["record_id"], 26 is_right_label = isRightID(data["record_id"]) 27 ) 28 recordid.save() 29 30def isHalfNum(str): 31 try: 32 int(str) 33 except ValueError: 34 return False 35 else: 36 for char in str: 37 if 'Na' != unicodedata.east_asian_width(char): 38 print("これは全角だ!") 39 return False 40 return True

views.py

Python

1from django.views.generic.edit import FormView, DeleteView 2from django.shortcuts import render, get_object_or_404, redirect 3from django.urls import reverse_lazy 4from django.views.generic import ListView 5 6 7from .forms import ContactForm 8from .models import RecordID 9 10class IndexView(FormView): 11 form_class = ContactForm 12 template_name = 'labelChecker/index.html' 13 success_url = reverse_lazy('labelChecker:index') 14 model = RecordID 15 16 def form_valid(self, form): 17 form.save() 18 super().form_valid(form) 19 20 def get_context_data(self, **kwargs): 21 context = super().get_context_data(**kwargs) 22 context = { 23 'recordid' : RecordID.objects.all() 24 } 25 return context

index.html

HTML

1{% for error in form.non_field_errors %} 2<div class="alert alert-danger"> 3 {{ error }} 4</div> 5{% endfor %}

試したこと

  1. get_context_data()を使わずにform_valid()の中でモデルオブジェクトをレンダーする

      →formが無効の時はモデルオブジェクトが表示されなくなってしまうため×

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

解決方法

views.pyのget_context_data()の中身の記述が間違っていました。
折角、context = super().get_context_data()でformをcontextに代入したのに、その直後にcontextを上書きしたのが問題でした。
正しくはkwargsにモデルオブジェクトを追加してからcontext = super().get_context_dataします。

** 変更前**

def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context = { 'recordid' : RecordID.objects.all() } return context

** 変更後**

def get_context_data(self, **kwargs): kwargs['recordid'] = RecordID.objects.all() context = super().get_context_data(**kwargs) return context

理解したこと

FormViewの親の親クラスの内部は以下のようになっています。
参考: 小梅の日記帳, FormViewの継承関係を見てみる, 2019-7-29

class FormMixin(ContextMixin): [略] def form_invalid(self, form):     """If the form is invalid, render the invalid form."""     return self.render_to_response(self.get_context_data(form=form)) def get_context_data(self, **kwargs):      """Insert the form into the context dict."""     if 'form' not in kwargs:         kwargs['form'] = self.get_form()         return super().get_context_data(**kwargs)

投稿2021/12/09 08:32

Sora66

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問