【Django】バリデーション機能の実装パターンについて

# はじめに
DjangoのFormクラスを活用することで、フォーム入力値のバリデーションを簡単に実装することが出来ます。
複雑なパターンや入力制限をカスタマイズしたい場合を除き、基本的な要素はデフォルトで用意された処理をフォームクラスで実装します。

よく利用する基礎的なバリデーションパターンを記述していきます。

# 1. バリデーションの実装方法
まずはテンプレートで画面に表示するHTMLを実装します。
~~~html:html
<form action="{% url 'check' %}" method="post">
    {% csrf_token %}
    {{ form.as_table }}
    <input type="submit" value="click">
</form>
~~~

ビューでフォームクラスを呼び出して、入力値のバリデーションの結果を元に処理を分岐出来させられます。
~~~python:views.py
def check(request):
    params = {
        'form':CheckForm(),
    }
    # リクエストがPOSTの場合
    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)
~~~
フォームクラスにてチェック処理を実装することで、ボタン押下時にバリデーションを追加することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665882/7cdfba2a-1dfb-2b1b-3ff4-a41d0891cb2f.png)

# 2. バリデーションの種類
フォームには様々なプロパティを活用して、多様なバリデーションを実装することが出来ます。
バリデーションの種類とプロパティをいくつか紹介します。

## 2-1. テキスト入力フィールド
テキスト入力フィールドは、「__CharField__」を使用します。
* __required__
⇒ 必要要素。Trueの場合は必須項目になる。
* __empty_value__
⇒ 空の入力を許可。requiredとの違いは、「　」(スペース)の入力でエラーにならない点。

フォームクラスでの実装は以下のように行います。
~~~python:forms.py
class CheckForm(forms.Form):
    find = forms.CharField(label='Find', required=False, \
        widget=forms.TextInput(attrs={'class':'form-control'}))
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665882/ef077f7d-8757-33d6-8883-ae2425bca437.png)

## 2-2. 数値入力フィールド
数字を扱うフィールドは「__IntegerField__」を使用します。
以下のプロパティ

* __min_length, max_length__
⇒ 入力するテキストの最小文字数、最大文字数を指定する。

~~~python:forms.py
class CheckForm(forms.Form):
    requeired = forms.IntegerField(label='Requeired', \
        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'}))
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665882/30292d75-74fa-8c81-3264-2d8e12dd609f.png)

## 2-3. 日時関連フォーマット
日時関連のバリデーションでは、「__DateField__」「__TimeField__」「__DateTimeField__」が利用出来ます。
前半で紹介した「required」といったプロパティも当然利用できます。

| フォーマット | 意味 | 
|:-----------:|:------------:|
| %y       | 年を表す数字        |
| %m     | 月を表す数字      |
| %d       | 日を表す数字        |
| %H         | 時を表す数字       |
| %M       | 分を表す数字      |
| %S    | 秒を表す数字     |

上記のテキストフォーマットを活用して、「2024-04-01」のような形式の指定が可能です。
フォームでは以下のように実装します。
~~~python:forms.py
class CheckForm(forms.Form):
    date = forms.DateField(label="Date", input_formats=['%y/%m/%d'], \
        widget=forms.DateInput(attrs={'class':'form-control'}))
    time = forms.TimeField(label='Time', \
        widget=forms.TimeInput(attrs={'class':'form-control'}))
~~~
※ ビューの「is_valid関数」で分岐した処理により、「no good...」が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665882/cfe713dd-7f29-9431-bcbf-97db662de8e2.png)

# おわりに
バリデーション機能の実装がDjangoではデフォルトで用意されているので、基本的な要素はあえてカスタムせずにフォーマットとプロパティを書くだけで判定処理が実装出来ます。便利だなぁ。
この他にも色々な要素が用意されているので、調べて実践してみようと思います。