본글 : https://naruport.com/blog/2019/7/25/django-custom-form/
같이보면 좋은 자료 : https://developer.mozilla.org/ko/docs/Learn/Server-side/Django/Forms
煉獄!Djangoのフォームを俺好みに改造する
目次
はじめに
以下のようなフォームがある。
# forms from django import forms class ProfileForm(forms.Form): name = forms.CharField() age = forms.IntegerField()
# templates <form action="{% url 'index' %}" method="POST"> {% csrf_token %} {{ profile_form }} <input type="submit" value="送信"> </form>
# view
from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import NameForm def get_name(request): # if this is a POST request we need to process the form data if request.method == 'POST': # create a form instance and populate it with data from the request: form = NameForm(request.POST) # check whether it's valid: if form.is_valid(): # process the data in form.cleaned_data as required # ... # redirect to a new URL: return HttpResponseRedirect('/thanks/') # if a GET (or any other method) we'll create a blank form else: form = NameForm() return render(request, 'name.html', {'profile_form ': form})
これを改造していく。
Formの多様なフォーマット
BooleanField
, CharField
, ChoiceField
, TypedChoiceField
, DateField
, DateTimeField
, DecimalField
, DurationField
, EmailField
, FileField
, FilePathField
, FloatField
, ImageField
, IntegerField
, GenericIPAddressField
, MultipleChoiceField
, TypedMultipleChoiceField
, NullBooleanField
, RegexField
, SlugField
, TimeField
, URLField
, UUIDField
, ComboField
, MultiValueField
, SplitDateTimeField
, ModelMultipleChoiceField
, ModelChoiceField
.
(https://developer.mozilla.org/ko/docs/Learn/Server-side/Django/Forms)
フィールドを参照する
テンプレート内でフォームのフィールド名を参照すると対応するフィールドが取り出せる。
from django import forms class ProfileForm(forms.Form): name = forms.CharField() age = forms.IntegerField()
{% with profile_form as f %} <form action="{% url 'index' %}" method="POST"> {% csrf_token %} <div>{{ f.name }}</div> <div>{{ f.age }}</div> <input type="submit" value="送信"> </form> {% endwith %}
しかしインプット要素のみの取り出しなので味気がない出力になる。
ラベルを参照する
ラベル名を参照するにはフィールドのlabel
を参照する。ちなみにlabel
名の参照ではHTML
のlabel
は生成されないので、別途タグで囲む必要がある。
{% with profile_form as f %} <form action="{% url 'index' %}" method="POST"> {% csrf_token %} <div><label>{{ f.name.label }}</label>: {{ f.name }}</div> <div><label>{{ f.age.label }}</label>: {{ f.age }}</div> <input type="submit" value="送信"> </form> {% endwith %}
ラベル名を変更するにはフォームのフィールドのlabel
を指定する。
from django import forms class ProfileForm(forms.Form): name = forms.CharField(label='名前') age = forms.IntegerField(label='年齢')
대부분의 필드에 공통적인 인자들은 아래와 같다. ( 이들은 적절한 기본값을 가지고 있다 ):
- required:
True
로 설정되면, 필드를 빈칸으로 두거나None
값을 줄 수 없게된다. 보통필드는 required는 True로 기본 설정되므로, 폼에서 빈 칸을 허용하기 위해서는required=False
로 설정해야 한다. - label: HTML에서 필드를 렌더링할때 사용하는 레이블이다. label 이 지정되지 않으면, Django는 필드 이름에서 첫번째 문자를 대문자로, 밑줄을 공백으로 변형한 레이블을 새로 생성할 것이다. (예를 들면, renewal_date --> Renewal date).
- label_suffix: 기본적으로, 콜론(:)이 레이블 다음에 표시된다. (예를 들면, Renewal date:). 이 인자는 다른 문자(들)를 포함한 접미사를 지정할 수 있도록 해준다.
- initial: 폼이 나타날 때 해당 필드의 초기 값.
- widget: 사용할 디스플레이 위젯.
- help_text (위의 예에서 봤듯이): 필드 사용법을 보여주는 추가적인 문구.
- error_messages: 해당 필드의 에러 메시지 목록. 필요하면 문구를 수정할 수 있다.
- validators: 해당 필드가 유효한 값을 가질 때 호출되는 함수의 목록.
- localize: 폼 데이타 입력의 현지화(localisation)를 허용함 (자세한 정보는 해당 링크 참조).
- disabled: 이 옵션이
True
일때 해당 필드를 볼 수는 있지만 편집이 안됨. 기본 값은False
.
出力結果。
ヘルプの参照
フォームのフィールドにhelp_text
を設定した場合、テンプレートではフィールドのhelp_text
から設定文字列を参照できる。
from django import forms class ProfileForm(forms.Form): name = forms.CharField(label='名前', help_text='英字のみ') age = forms.IntegerField(label='年齢', help_text='0以上120以下')
{% with profile_form as f %} <form action="{% url 'index' %}" method="POST"> {% csrf_token %} <div> <label>{{ f.name.label }}</label>: {{ f.name }} <p>{{ f.name.help_text }}</p> </div> <div> <label>{{ f.age.label }}</label>: {{ f.age }} <p>{{ f.age.help_text }}</p> </div> <input type="submit" value="送信"> </form> {% endwith %}
出力結果。
エラーの参照
フォームは検証に失敗するとエラー文字列をフォームに格納する。
{% with profile_form as f %} <form action="{% url 'index' %}" method="POST"> {% csrf_token %} {# フィールドに属さない全体的なエラーの参照 #} {% if f.errors %} <p>{{ f.non_field_errors }}</p> {% endif %} <div> <label>{{ f.name.label }}</label>: {{ f.name }} <p>{{ f.name.help_text }}</p> {# フィールドに属しているエラーの参照 #} <p>{{ f.name.errors }}</p> </div> <div> <label>{{ f.age.label }}</label>: {{ f.age }} <p>{{ f.age.help_text }}</p> {# フィールドに属しているエラーの参照 #} <p>{{ f.age.errors }}</p> </div> <input type="submit" value="送信"> </form> {% endwith %}
バリデーションの追加
バリデーションを追加するにはフォームにclean_
で始まるメソッドを定義する(参照: http://python.keicode.com/django/form-validation.php)。
デフォルトのバリデーターが呼ばれた後に実行されるらしい。
from django import forms class ProfileForm(forms.Form): name = forms.CharField(max_length=20, label='名前', help_text='英字のみ') age = forms.IntegerField(label='年齢', help_text='0以上120以下') def clean_name(self): # viewのform.is_validが実行されるとdef clean_xxxx系の関数から有効性検査を行う name = self.cleaned_data['name'] isallalpha = True for c in name: if not c.isalpha(): isallalpha = False break if not isallalpha: raise forms.ValidationError('英字以外が含まれています。') return name def clean_age(self): """ ちなみにフィールドの属性 min_value, max_valueで入力範囲を制限できる。 それらを設定したらこのバリデーションは不要? """ age = self.cleaned_data['age'] if age < 0 or age > 120: raise forms.ValidationError('範囲外です。') return age
フォームに不正な値を入力してみた出力結果。
ちなみにテンプレートでerrors
を参照したい場合、views.py
でちょっとした工夫が必要になる。is_valid
を呼んだ後のフォームを再度出力用のテンプレートに渡すとerrors
を参照できるようになる。
from django.shortcuts import render from django.http import HttpResponse from . import forms def index(req): if req.method == 'GET': return render(req, 'myapp/profile-form.html', { 'profile_form': forms.ProfileForm(), }) elif req.method == 'POST': profile_form = forms.ProfileForm(req.POST) if not profile_form.is_valid(): # ここでerrorsを生かしたままテンプレートに渡す。 return render(req, 'myapp/profile-form.html', { 'profile_form': profile_form, }) return HttpResponse('ok')
プレースホルダーの設定
インプット要素のプレースホルダーはフォームのwidget
で設定できる。widget
の種類は https://github.com/django/django/blob/master/django/forms/widgets.py を参照。
class ProfileForm(forms.Form): name = forms.CharField(max_length=20, label='名前', help_text='英字のみ', widget=forms.TextInput(attrs={ 'placeholder': 'Name', })) age = forms.IntegerField(min_value=0, max_value=120, label='年齢', help_text='0以上120以下', widget=forms.NumberInput(attrs={ 'placeholder': '0', }))
出力結果。
だいぶフォームらしくなりました(・∀・)ノ
'frameworks > django' 카테고리의 다른 글
커스텀 템플릿태그(templatetags) 응용하기 (0) | 2019.09.17 |
---|---|
reverse, resolve_url이 뭘까? : django.urls utility functions (0) | 2019.09.10 |
django template에서 customizing 필터를 사용하는 법 (0) | 2019.09.04 |
httpResponse, HttpResponseRedirect, render, redirect 의 차이 (0) | 2019.09.02 |
Python + Django로 독자의 유저인증 페이지 만들기 (0) | 2019.09.02 |