2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

クラスベースビューにおける form_invalid のときにエラーメッセージを返したいときの処置

Last updated at Posted at 2020-05-01

はじめに

Djangoの Class-Based-View でフォームバリデーションの仕組みを構築していたときに沼にハマったのでメモ

urls

http://www.henojiya.net/ と入力されたら IndexView を呼び出せ

urls.py
app_name = 'shp'
urlpatterns = [
    path('', IndexView.as_view(), name='index'),

views

テンプレートと関連付けるデータを引き連れ、index.htmlを表示させる

views.py
class IndexView(TemplateView):
    # 表示するテンプレート: index.html
    template_name = 'shopping/index.html'

    # テンプレートに引き連れていく各種データやフォーム
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['products'] = Products.objects.all()
        context['form_single'] = SingleRegistrationForm()
        context['form_csv'] = UploadCSVForm()
        context['editablelist'] = Products.objects.order_by('id')[:5]
        context['editableform'] = EditForm()
        return context

CSVをアップロードするためだけのhtml

index.html にはCSVをアップロードするためだけのフォームを作成する
image.png
formがsubmitされると regist_bulk に飛べと書いてある。

index.html
...省略...
    <h3>CSV登録</h3>
    <form action="{% url 'shp:regist_bulk' %}" method="POST" class="registration" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form_csv.as_p }}
        <input type="submit" value="UPLOAD">
    </form>
...省略...

urls

regist_bulk が呼ばれたら UploadBulkView を呼び出せ

urls.py
app_name = 'shp'
urlpatterns = [
    path('regist/bulk/', UploadBulkView.as_view(), name='regist_bulk'),

views

UploadBulkView が呼ばれると、バリデーションがうまくいったときとうまくいかなかったときの処理を上書きできる仕組みが用意されている。今回はバリデーションでハジかれたときにフォーカスする。この form_invalid に行く前に、フォームのフィールドごとのバリデーションが走る。

views.py
class UploadBulkView(FormView):
    """UploadBulkView"""
    form_class = UploadCSVForm
    success_url = reverse_lazy('shp:index')

    # バリデーションがうまくいったとき
    def form_valid(self, form):
        ...省略...

    # バリデーションがうまくいかなかったとき
    def form_invalid(self, form):
        messages.add_message(self.request, messages.WARNING, form.errors)
        return redirect('shp:index')

フォームのフィールドごとのバリデーション

clean_(field_name)というメソッドをつくるとフィールドごとのバリデーションができる。今回は csv 以外をアップロードしていないかをチェックした。

forms.py
class UploadCSVForm(forms.Form):
    """ formのname 属性が 'file' になる """
    file = forms.FileField(required=True, label='')

    def clean_file(self):
        """csvファイル要件を満たすかどうかをチェックします"""
        file = self.cleaned_data['file']
        if not file.name.endswith('.csv'):
            raise forms.ValidationError('拡張子はcsvのみです')
        return file

ValidationError にメッセージを仕込んで raise するとサーバーサイドでのprintをしたときにこんなhtmlが入っていた。

print(ValidationError)
<ul class="errorlist">
  <li>file
    <ul class="errorlist">
      <li>拡張子はcsvのみです</li>
    </ul>
  </li>
</ul>

views

さて、バリデーションが終わると、form_invalidの処理に流れる。バリデーションが失敗したら、エラーメッセージとともに元のページにリダイレクトするっていうのはよくありそうな処理じゃん?でもリダイレクト時にエラーメッセージを持っていけないのよwwwゴーギャーン!:rage:って感じやん。だから、「form」の引数の「form.errors」に入っているhtmlを messages に渡して、その後にシンプルなリダイレクトという手段を取った。

views.py
class UploadBulkView(FormView):
    """UploadBulkView"""
    form_class = UploadCSVForm
    success_url = reverse_lazy('shp:index')

    # バリデーションがうまくいったとき
    def form_valid(self, form):
        ...省略...

    # バリデーションがうまくいかなかったとき
    def form_invalid(self, form):
        messages.add_message(self.request, messages.WARNING, form.errors)
        return redirect('shp:index')

Tips: 元のページにもどる

views.py
class UploadBulkView(FormView):
    """UploadBulkView"""
    form_class = UploadCSVForm
    success_url = reverse_lazy('shp:index')

    # バリデーションがうまくいったとき
    def form_valid(self, form):
+       return super().form_valid(form)  # あれ、こっちうまくいかねーな...redirectしか無いかな?

    # バリデーションがうまくいかなかったとき
    def form_invalid(self, form):
        messages.add_message(self.request, messages.WARNING, form.errors)
+       return super().form_invalid(form)

最終結果

htmlにエラーhtmlを表示する記述を追加。とりあえずオッケー!:fist:

index.html
    {% if messages %}
        {% for message in messages %}
        {{ message }}
        {% endfor %}
    {% endif %}

image.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?