【clean】djangoでフォームを複数のカラムにまたがって入力チェックする

【clean】djangoでフォームを複数のカラムにまたがって入力チェックする

参考:
  ・Djangoのforms.pyでメソッドを使ったフォームのバリデーション
  ・Django、フォームの表示方法まとめ

挙動

挙動は下の通りです。タイトルとテキストの組み合わせが重複しているとエラーが出て登録を出来ないようにしています。

プログラム

【ルーティング】


# config/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp.urls')),
]

# myapp/urls.py
from django.urls import path
from . import views

app_name = 'myapp'
urlpatterns = [
    path('blog_form/', views.blog_form, name='blog_form'),
]

【モデル】


# myapp/models.py
from django.db import models

class Blog(models.Model):
    title = models.CharField(blank=False, null=False, max_length=150)
    text  = models.TextField(blank=True)
    created_datetime = models.DateTimeField(auto_now_add=True)
    updated_datetime = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

【フォーム】
肝になるのはここだけですね。cleanメソッドで入力値が既に登録済みであるかチェックしています。登録済みであればエラーを発生させます。


from django.core.exceptions import ValidationError
from django.forms import ModelForm
from django import forms
from .models import Blog

class BlogForm(forms.Form):
    title = forms.CharField(
        label='タイトル',
        required=True,
        max_length=150,
    )
    text = forms.CharField(
        label='テキスト',
        required=True,
        max_length=500,
        widget=forms.Textarea,
    )

    def clean(self):
        title = self.cleaned_data['title']
        text = self.cleaned_data['text']
        blog = Blog.objects.filter(
            title=title,
            text=text,
        ).exists()
        if blog:
            raise ValidationError('入力したタイトルとテキストの組み合わせは既に登録済みです。')

【ビュー】


# myapp/views.py
from django.shortcuts import render
from myapp.models import Blog
from myapp.forms import BlogForm

def blog_form(request):
    form = BlogForm
    if request.method == 'POST':
        form = BlogForm(request.POST)
        if form.is_valid():
            blog = Blog.objects.create(
                title=form.cleaned_data['title'],
                text=form.cleaned_data['text'],
            )
    context = {
        'form': form
    } 
    return render(request, 'myapp/blog_form.html', context)

【テンプレート】
発生させたエラーのメッセージをfor文で回して取り出し表示しています。


<!--templates/myapp/blog_form.html-->
<form action="{% url 'myapp:blog_form' %}" method="POST">{% csrf_token %}
    <div>title:</div>
    <dv>{{ form.title }}</div>
    <br>
    <div>text:</div>
    <div>{{ form.text }}</div>
    <br>
    <button type="submit">save</button>
</form>
{% if form.non_field_errors %}
    {% for error in form.non_field_errors %}
        
{{ error }}
{% endfor %} {% endif %}

関連のある書籍