Python | Django | フォームにおけるバリデーションの使い方

2021年7月8日

公開日:2021/7/8

Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.

前記事にて,「フォームにおけるフィールドの使い方」を記した.前記事での設定をそのまま引き継いだ上で,本記事では,「フォームにおけるバリデーションの使い方」を以下3つの構成にて記す.

  1. “clean"を利用するバリデーション
  2. “validators"を利用するバリデーション
  3. 複数の箇所にバリデーション

◆実施環境

Python 3.8.8
Django 3.2.3

■フォームにおけるフィールドの使い方

  1. “clean"を利用するバリデーション

前記事で作成した以下ページ(“http://127.0.0.1:8000/form_application/form_page/")において,本項では,"チョコレート名"に入力制限をかける.

“form_app/forms.py"に追記し,以下のように編集する."チョコレート名"に入力する際,"F"から始めないとエラーが出るようなコードを追記した.

from django import forms

class ChocolateInfo(forms.Form):
  chocolate_name = forms.CharField(label='チョコレート名', max_length=50)
  chocolate_maker = forms.CharField(label='チョコレートメーカー', max_length=50)
  mail = forms.EmailField(label='メールアドレス')
  is_available_for_sale = forms.BooleanField(label='販売中')
  birthday = forms.DateField(required=False, label='開発日')
  price = forms.DecimalField(initial=300, max_value=1000, label='価格')
  
  flavor = forms.ChoiceField(choices=(
    (1,'Original Chocolat'),
    (2,'Double Chocolat'),
    (3,'Original White'),
    (4,'Rich Matcha'),
  ), widget=forms.RadioSelect, label='味')
  
  maker_factory = forms.MultipleChoiceField(choices=(
    (1,'Ibaraki Moriya-city'),
    (2,'Saitama Sakado-city'),
    (3,'Aichi Inazawa-city'),
    (4,'Osaka Takatsuki-city'),
  ), widget=forms.CheckboxSelectMultiple, label='メーカー工場')
  
  homepage = forms.URLField(
    label='ホームページ',
    widget=forms.TextInput(attrs={'class':'url_class','placeholder':'https://www.shelokuma.com'})
  )

def __init__(self,*args,**kwargs):
  super(ChocolateInfo, self).__init__(*args,**kwargs)
  self.fields['flavor'].widget.attrs['id']='id_flavor'
  self.fields['maker_factory'].widget.attrs['class']='maker_factory_class'

def clean_chocolatename(self): # 以下追記箇所
  chocolate_name = self.cleaned_data['chocolate_name']
  if not chocolate_name.startswith('F'):
      raise forms.ValidationError('名前は「F」から始めてください')

ターミナルを開き,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら).”form_project”のディレクトリで”python manage.py runserver”を実行する.私の場合,以下のように実行する.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myformtest\form_project
>python manage.py runserver

実行すると,ターミナルに以下が出力される.

System check identified no issues (0 silenced).
July 08, 2021 - 13:25:33
Django version 3.2.3, using settings 'form_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

“http://127.0.0.1:8000/”をクリックし,ブラウザを開くと以下のように表示される.

“http://127.0.0.1:8000/form_application”をクリックし,ブラウザを開くと以下のように表示される.

上記の"Go to Form"をクリックすると以下ページ(“http://127.0.0.1:8000/form_application/form_page/")に遷移する.

以下にて,チョコレート名を"F"から始まらない"aaaaa"にし,"submit"をクリックすると,赤枠にエラーが出現する.

以下のように,チョコレート名を"F"から始まるように修正し,"submit"をクリックするとエラーは出現しない.

ターミナルには,以下のように上記で入力した内容が出力された.

submission is successful
{'chocolate_name': 'Faaa', 'chocolate_maker': 'Meiji', 
'mail': 'Faaa@gmail.com', 'is_available_for_sale': True, 
'birthday': datetime.date(1999, 1, 1), 'price': Decimal('300'), 
'flavor': '3', 'maker_factory': ['1', '2'], 
'homepage': 'https://www.google.com'}
  1. “validators"を利用するバリデーション

以下ページ(“http://127.0.0.1:8000/form_application/form_page/")で"価格"に入力制限をかける.

“form_app/forms.py"の2行目と10行目に追記し,以下のように編集する.価格を入力する際,1未満だとエラーが出るようなコードを追記した.

from django import forms
from django.core import validators # 追記箇所

class ChocolateInfo(forms.Form):
  chocolate_name = forms.CharField(label='チョコレート名', max_length=50)
  chocolate_maker = forms.CharField(label='チョコレートメーカー', max_length=50)
  mail = forms.EmailField(label='メールアドレス')
  is_available_for_sale = forms.BooleanField(label='販売中')
  birthday = forms.DateField(required=False, label='開発日')
  price = forms.DecimalField(initial=300, max_value=1000, label='価格',validators=[validators.MinValueValidator(1, message='1以上にしてください')]) # 追記箇所
  
  flavor = forms.ChoiceField(choices=(
    (1, 'Original Chocolat'),
    (2, 'Double Chocolat'),
    (3, 'Original White'),
    (4, 'Rich Matcha'),
  ), widget=forms.RadioSelect, label='味')
  
  maker_factory = forms.MultipleChoiceField(choices=(
    (1, 'Ibaraki Moriya-city'),
    (2, 'Saitama Sakado-city'),
    (3, 'Aichi Inazawa-city'),
    (4, 'Osaka Takatsuki-city'),
  ), widget=forms.CheckboxSelectMultiple, label='メーカー工場')
  
  homepage = forms.URLField(
    label='ホームページ',
    widget=forms.TextInput(attrs={'class':'url_class','placeholder':'https://www.shelokuma.com'})
  )

  def __init__(self,*args,**kwargs):
    super(ChocolateInfo, self).__init__(*args, **kwargs)
    self.fields['flavor'].widget.attrs['id'] = 'id_flavor'
    self.fields['maker_factory'].widget.attrs['class'] = 'maker_factory_class'

  def clean_chocolatename(self):
    chocolate_name = self.cleaned_data['chocolate_name']
    if not chocolate_name.startswith('F'):
      raise forms.ValidationError('名前は「F」から始めてください')

ターミナルを開き,仮想環境に移行し,”form_project”のディレクトリで”python manage.py runserver”を実行すると以下が出力される.

System check identified no issues (0 silenced).
July 08, 2021 - 13:25:33
Django version 3.2.3, using settings 'form_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

“http://127.0.0.1:8000/”をクリックし,ブラウザを開くと以下のように表示される.

その後,以下ページ(“http://127.0.0.1:8000/form_application/form_page/")に遷移し,各項目を入力をし,"submit"をクリックする.価格が1未満である"0″だったため,エラーが出現した.

以下のように,価格を1以上に修正し,"submit"をクリックするとエラーは出現しない.

ターミナルには,以下のように上記で入力した内容が出力された.

submission is successful
{'chocolate_name': 'Fran10', 'chocolate_maker': 'Meiji', 
'mail': 'Fran10@gmail.com', 'is_available_for_sale': True, 
'birthday': datetime.date(1999, 1, 1), 'price': Decimal('1'), 
'flavor': '1', 'maker_factory': ['2'], 
'homepage': 'https://www.google.com'}
  1. 複数の箇所にバリデーション

以下ページ(“http://127.0.0.1:8000/form_application/form_page/")の"メールアドレス"の下に"メールアドレス再入力"を作成し,メールアドレスの一致確認をする.

“form_app/forms.py"の8行目と41行目に追記し,以下のように編集する."メールアドレス"の下に"メールアドレス再入力"を作成し,メールアドレスが同じでないとエラーを出現させるようなコードを追記した.

from django import forms
from django.core import validators

class ChocolateInfo(forms.Form):
  chocolate_name = forms.CharField(label='チョコレート名', max_length=50)
  chocolate_maker = forms.CharField(label='チョコレートメーカー', max_length=50)
  mail = forms.EmailField(label='メールアドレス')
  confirmed_mail = forms.EmailField(label='メールアドレス再入力') # 追記箇所
  is_available_for_sale = forms.BooleanField(label='販売中')
  birthday = forms.DateField(required=False, label='開発日')
  price = forms.DecimalField(initial=300, max_value=1000, label='価格',validators=[validators.MinValueValidator(1, message='1以上にしてください')])

  flavor = forms.ChoiceField(choices=(
    (1, 'Original Chocolat'),
    (2, 'Double Chocolat'),
    (3, 'Original White'),
    (4, 'Rich Matcha'),
  ), widget=forms.RadioSelect, label='味')
  
  maker_factory = forms.MultipleChoiceField(choices=(
    (1, 'Ibaraki Moriya-city'),
    (2, 'Saitama Sakado-city'),
    (3, 'Aichi Inazawa-city'),
    (4, 'Osaka Takatsuki-city'),
  ), widget=forms.CheckboxSelectMultiple, label='メーカー工場')
  homepage = forms.URLField(
    label='ホームページ',
    widget=forms.TextInput(attrs={'class':'url_class','placeholder':'https://www.shelokuma.com'})
  )

  def __init__(self,*args,**kwargs):
    super(ChocolateInfo, self).__init__(*args, **kwargs)
    self.fields['flavor'].widget.attrs['id'] = 'id_flavor'
    self.fields['maker_factory'].widget.attrs['class'] = 'maker_factory_class'

  def clean_chocolatename(self):
    chocolate_name = self.cleaned_data['chocolate_name']
    if not chocolate_name.startswith('F'):
      raise forms.ValidationError('名前は「F」から始めてください')

  def clean(self): # 以下追記箇所
    cleaned_data = super().clean()
    mail = cleaned_data['mail']
    confirmed_mail = cleaned_data['confirmed_mail']
    if mail != confirmed_mail:
      raise forms.ValidationError('メールアドレスが一致しません')

以下ページ(“http://127.0.0.1:8000/form_application/form_page/")に遷移し,各項目を入力をし,"submit"をクリックする."メールアドレス"と"メールアドレス再入力"が異なる内容だったため,エラーが出現した.

以下のように,"メールアドレス"と"メールアドレス再入力"を同じにし,"submit"をクリックするとエラーは出現しない.

ターミナルには,以下のように上記で入力した内容が出力された.

submission is successful
{'chocolate_name': 'Fran100', 'chocolate_maker': 'Meiji', 
'mail': 'Fran100@gmail.com', 'confirmed_mail': 'Fran100@gmail.com', 
'is_available_for_sale': True, 'birthday': datetime.date(2000, 1, 1), 
'price': Decimal('400'), 'flavor': '1', 'maker_factory': ['1', '2'], 
'homepage': 'https://www.yahoo.co.jp'}

■参照

https://docs.djangoproject.com/ja/3.1/ref/validators/

以上