バリデーションはフォームなどの入力項目に条件を設定し、その条件を満たしているかどうかを確認する機能です。
Contents
forms.Formのバリデーション
まずはモデルを使わない一般的なフォームでのバリデーションについて見てみましょう。
hello/forms.py
class HelloForm(forms.Form):
name = forms.CharField(label='Name', \
widget=forms.TextInput(attrs={'class':'form-control'}))
mail = forms.EmailField(label='Email', \
widget=forms.EmailInput(attrs={'class':'form-control'}))
gender = forms.BooleanField(label='Gender', required=False, \
widget=forms.CheckboxInput(attrs={'class':'form-check'}))
age = forms.IntegerField(label='Age', \
widget=forms.NumberInput(attrs={'class':'form-control'}))
birthday = forms.DateField(label='Birth', \
widget=forms.DateInput(attrs={'class':'form-control'}))
gender部分の引数に下記の設定があります。
これこそがバリデーションの設定なのです。Falseにすることでバリデーション必須ではなくなります。
required=False
それでは、チェック用のテンプレート check.htmlを作成して使ってみましょう。
/hello/templates/hello/check.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
rel="stylesheet" crossorigin="anonymous">
</head>
<body class="container">
<h1 class="display-4 text-primary">
{{title}}</h1>
<p>{{message|safe}}</p>
<form action="{% url 'check' %}" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="click"
class="btn btn-primary mt-2">
</form>
</body>
</html>
urlpatternsの追記
/hello/urls.py
from django.urls import path
from . import views
urlpatterns = [
・・
path('check', views.check, name='check'), #追加
]
CheckFormの作成
/hello/forms.py
from django import forms
from.models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name','mail','gender','age','birthday']
class FindForm(forms.Form):
find = forms.CharField(label='Find', required=False, \
widget=forms.TextInput(attrs={'class':'form-control'}))
class HelloForm(forms.Form):
name = forms.CharField(label='Name', \
widget=forms.TextInput(attrs={'class':'form-control'}))
mail = forms.EmailField(label='Email', \
widget=forms.EmailInput(attrs={'class':'form-control'}))
gender = forms.BooleanField(label='Gender', required=False, \
widget=forms.CheckboxInput(attrs={'class':'form-check'}))
age = forms.IntegerField(label='Age', \
widget=forms.NumberInput(attrs={'class':'form-control'}))
birthday = forms.DateField(label='Birth', \
widget=forms.DateInput(attrs={'class':'form-control'}))
class CheckForm(forms.Form): #追加
str = forms.CharField(label='Name',\
widget=forms.TextInput(attrs={'class':'form-control'}))
views.pyにCheck関数を作成します。
/hello/views.py
from .forms import CheckForm #☆
def check(request):
params = {
'title': 'Hello',
'message':'check validation.',
'form': CheckForm(),
}
if (request.method == 'POST'):
form = CheckForm(request.POST)
params['form'] = form
if (form.is_valid()):
params['message'] = 'OK!'
else:
params['message'] = 'no good.'
return render(request, 'hello/check.html', params)
コードの以下の部分にてバリデーションチェックを行っています。
if (form.is_valid()):
params['message'] = 'OK!'
else:
params['message'] = 'no good.'
webブラウザにてアクセスします。
Nameが未入力だとエラーメッセージが表示されます。
半角スペースだけを入力すると、「This field is required.」のエラーメッセージが表示されます。
どんなバリデーションがあるか?
CharFieldのバリデーション
最も基本となるテキスト入力フィールド「CharField」に用意されているバリデーションには下記のものがあります。
#必須項目チェック
require
#最小文字数、最大文字数
min_length, max_length
#空の入力許可するか
empty_value
それでは、min_length, max_lengthのバリデーションを試してみましょう。
/hello/forms.py
class CheckForm(forms.Form):
empty = forms.CharField(label='Empty', empty_value=True, \
widget=forms.TextInput(attrs={'class':'form-control'}))
min = forms.CharField(label='Min', min_length=10, \
widget=forms.TextInput(attrs={'class':'form-control'}))
max = forms.CharField(label='Max', max_length=10, \
widget=forms.TextInput(attrs={'class':'form-control'}))
MinもMaxも10文字を指定しました。Maxは10文字以下しか入力できなくなります。
webブラウザにてアクセスします。
IntegerField/FloatFieldのバリデーション
「IntegerField」に用意されているバリデーションには下記のものがあります。
required
min_value, max_value
それでは、min_value, max_valueのバリデーションを試してみましょう。
forms.pyのCheckFormクラスを修正します。
min_value=100、max_value=1000を指定してあります。
/hello/forms.py
class CheckForm(forms.Form):
required = forms.IntegerField(label='Required', \
widget=forms.NumberInput(attrs={'class':'form-control'}))
min = forms.IntegerField(label='Min', min_value=100, \
widget=forms.NumberInput(attrs={'class':'form-control'}))
max = forms.IntegerField(label='Max', max_value=1000, \
widget=forms.NumberInput(attrs={'class':'form-control'}))
webブラウザにてアクセスします。
日付関連のバリデーション
DateField、TimeField、DateTimeFieldというった日付関連のフィールドには、requiredの他にフォーマットに関するバリデーションが設定されています。この日時のフォーマットは「input_formats」という引数で指定することができます。
input_formats = [フォーマット1, フォーマット2, ・・]
フォーマットの書き方
%y | 年を表す数字 |
%m | 月を表す数字 |
%d | 日を表す数字 |
%H | 時を表す数字 |
%M | 分を表す数字 |
%S | 秒を表す数字 |
forms.pyのCheckForm関数を下記のように修正します。
dateは1~31の数値、Timeは「時:分」、DateTimeは「年-月-日 時:分」というフォーマットにして指定します。
/hello/forms.py
class CheckForm(forms.Form):
date = forms.DateField(label='Date', input_formats=['%d'], \
widget=forms.DateInput(attrs={'class':'form-control'}))
time = forms.TimeField(label='Time', \
widget=forms.TimeInput(attrs={'class':'form-control'}))
datetime = forms.DateTimeField(label='DateTime', \
widget=forms.DateTimeInput(attrs={'class':'form-control'}))
webブラウザにてアクセスします。
全てエラーになる場合
入力OKの場合
バリデーションを追加する
デフォルトのバリデーション以外に、「こういうときにバリデーションエラーになってほしい」ということがあります。このような場合は、Formクラスにメソッドを追加します。
class クラス名(forms.Form)
def clean(self):
変数=super().clean()
cleanというメソッドは、用意された値の検証を行う際に呼び出されます。
このメソッドでは最初にsuper().clean()というものを呼び出して、基底クラス(継承元のクラス)のcleanを呼び出します。戻り値にはチェック済みの値が返されます。また下記の定義により任意にエラーを発生させることができます。
raise ValidationError(エラーメッセージ)
それでは実際にエラーを発生させてみます。
forms.pyのCheckFormクラスを下記にように修正します。
/hello/forms.py
from django import forms #☆
class CheckForm(forms.Form):
str = forms.CharField(label='String', \
widget=forms.TextInput(attrs={'class':'form-control'}))
def clean(self):
cleaned_data = super().clean()
str = cleaned_data['str']
if (str.lower().startswith('no')):
raise forms.ValidationError('You input "NO"!')
「NO」と入力すると’You input “NO”!’というエラーメッセージが表示されます。
ModelFormでのバリデーション
Djangoには、forms.Formを使った一般的なフォームのバリデーション以外に、ModelFormを使ったバリデーションがあります。
/hello/forms.py
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name','mail','gender','age','birthday']
/hello/models.py
class Friend(models.Model):
name = models.CharField(max_length=100)
mail = models.EmailField(max_length=200)
gender = models.BooleanField()
age = models.IntegerField(default=0)
birthday = models.DateField()
このバリデーションは「save」をクリックしたときに、バリデーションチェックが行われます。
/hello/views.py
def create(request):
if (request.method == 'POST'):
obj = Contact()
contact= ContactForm(request.POST, instance=obj)
contact.save()
return redirect(to='/hello')
params = {
'title': 'Hello',
'form': ContactForm(),
}
return render(request, 'hello/create.html', params)
「save」時以外でチェックを行わせる場合、「is_valid」メソッドを使ってチェックを行うことができます。
/hello/views.py
def check(request):
params = {
'title': 'Hello',
'message':'check validation.',
'form': ContactForm(),
}
if (request.method == 'POST'):
obj = Contact()
form = ContactForm(request.POST, instance=obj)
params['form'] = form
if (form.is_valid()):
params['message'] = 'OK!'
else:
params['message'] = 'no good.'
return render(request, 'hello/check.html', params)
/hello/templates/hello/check.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
rel="stylesheet" crossorigin="anonymous">
</head>
<body class="container">
<h1 class="display-4 text-primary">
{{title}}</h1>
<p>{{message|safe}}</p>
<form action="{% url 'check' %}" method="post">
{% csrf_token %}
<table class="table">
{{ form.as_table }}
<tr><th></th><td>
<input type="submit" value="click"
class="btn btn-primary mt-2">
</td></tr>
</table>
</form>
</body>
</html>
問題がなければ「OK」と表示される。
モデルで使えるバリデータ
MinValueValidator/MaxValueValidator
数値の最大値、最小値をチェック
MinValidator(値)
MaxValidator(値)
MinLengthValidator/MaxLengthValidator
テキストの最大文字数、最小文字数をチェック
MinLengthValidator(値)
MaxLengthValidator(値)
下記のようにコーディングします。
/hello/models.py
from django.db import models
from django.core.validators import MinLengthValidator #☆
class Contact(models.Model):
name = models.CharField(max_length=100, \
validators=[MinLengthValidator(10)])
mail = models.EmailField(max_length=200, \
validators=[MinLengthValidator(10)])
gender = models.BooleanField()
age = models.IntegerField()
birthday = models.DateField()
def __str__(self):
return '<Contact:id=' + str(self.id) + ', ' + \
self.name + '(' + str(self.age) + ')>'
nameとmailは10文字以内だとバリデータエラーになります。
EmailValidator/URLValidator
メールアドレスやURLのバリデーションチェックを行うことができます。
nameにバリデータを設定してみます。
/hello/models.py
from django.db import models
from django.core.validators import URLValidator #☆
class Contact(models.Model):
name = models.CharField(max_length=100, \
validators=[URLValidator()])
mail = models.EmailField(max_length=200)
gender = models.BooleanField()
age = models.IntegerField()
birthday = models.DateField()
def __str__(self):
return '<Contact:id=' + str(self.id) + ', ' + \
self.name + '(' + str(self.age) + ')>'
NameにURL以外を入力するとエラーになります。
ProhibitNullCharactersValidator
null文字を禁止するためのバリデータです。
RegexValidator
これは正規表現パターンを使って、パターンに合致する値かどうかをチェックするためのものです。
validators = [RegexValidator(r'^[a-z]*$')]
フォームとエラーメッセージを個別に表示
check,htmlを修正することで、フォームとエラーメッセージを個別に表示させることができます。
/hello/check.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
rel="stylesheet" crossorigin="anonymous">
</head>
<body class="container">
<h1 class="display-4 text-primary">
{{title}}</h1>
<p>{{message|safe}}</p>
<ol class="list-group">
{% for item in form %}
<li class="list-group-item py-2">
{{ item.name }} ({{ item.value }})
:{{ item.errors.as_text }}</li>
{% endfor %}
</ol>
<table class="table mt-4">
<form action="{% url 'check' %}" method="post">
{% csrf_token %}
<tr><th>名前</th><td>{{ form.name }}</td></tr>
<tr><th>メール</th><td>{{ form.mail }}</td></tr>
<tr><th>性別</th><td>{{ form.gender }}</td></tr>
<tr><th>年齢</th><td>{{ form.age }}</td></tr>
<tr><th>誕生日</th><td>{{ form.birthday }}</td></tr>
<tr><td></td><td>
<input type="submit" value="click"
class="btn btn-primary">
</td></tr>
</form>
</table>
</body>
</html>
ウィジェット設定した場合
https://codor.co.jp/django/how-to-use-widget
/hello/forms.py
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name','mail','gender','age','birthday']
widgets = {
'name': forms.TextInput(attrs={'class':'form-control'}),
'mail': forms.EmailInput(attrs={'class':'form-control'}),
'age': forms.NumberInput(attrs={'class':'form-control'}),
'birthday': forms.DateInput(attrs={'class':'form-control'}),
}
/hello/check.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
rel="stylesheet" crossorigin="anonymous">
</head>
<body class="container">
<h1 class="display-4 text-primary">
{{title}}</h1>
<p>{{message|safe}}</p>
<ol class="list-group mb-4">
{% for item in form %}
<li class="list-group-item py-2">
{{ item.name }} ({{ item.value }})
:{{ item.errors.as_text }}</li>
{% endfor %}
</ol>
<form action="{% url 'check' %}" method="post">
{% csrf_token %}
<div class="form-group">名前{{ form.name }}</div>
<div class="form-group">メール{{ form.mail }}</div>
<div class="form-group">性別</th><td>{{ form.gender }}</div>
<div class="form-group">年齢</th><td>{{ form.age }}</div>
<div class="form-group">誕生日</th><td>{{ form.birthday }}</div>
<div class="form-group">
<input type="submit" value="click"
class="btn btn-primary">
</div>
</form>
</body>
</html>
この記事は役に立ちましたか?
もし参考になりましたら、下記のボタンで教えてください。
コメント