당신은 멋쟁이, 우리는 장고쟁이~

0%

폼을 사용하여 데이터 검증하기


Form.clean()


서로 의존되어 있는 필드들을 위한 커스텀 검증을 추가해야 할때는, 폼에 clean() 메서드를 써주면 됩니다.


Form.is_valid()


폼 객체의 기본 과제는, 데이터를 검증하는것입니다.


Bound 폼 인스턴스를 가지고, is_valid() 메서드를 호출하여 유효성 검증을 실행하고, 데이터가 유효했었는지 아닌지에 대한 불리언값을 반환합니다.


1
2
3
4
5
6
7
8
9
10
11
In [1]: data = {'subject': 'hello', 
...: 'message': 'Hi there',
...: 'sender': 'foo@example.com',
...: 'cc_myself': True}

In [2]: from forms_more_on_fields.forms import ContactForm

In [3]: f = ContactForm(data)

In [4]: f.is_valid()
Out[4]: True

유효하지 않은 데이터로도 시도해보기 위해서, 아래 예시에는 subject 필드가 비어있습니다 (모든 필드들이 채워져야 하는 폼이므로, 이것은 에러 입니다). 게다가, 아래 예시에서, sender 는 유효한 이메일 주소가 아니게 입력 된 폼입니다.



1
2
3
4
5
6
7
8
9
In [5]: data = {'subject': '', 
...: 'message': 'Hi there',
...: 'sender': 'invalid email address',
...: 'cc_myself': True}

In [6]: f = ContactForm(data)

In [7]: f.is_valid()
Out[7]: False



더 읽어보기 »

Form API


Bound and Unbound Forms


하나의 폼 인스턴스는 bound 혹은 unbound 로 종류가 나뉩니다.


Bound Form


폼이 Bound 되어있다라는 표현은, 데이터가 폼에 묶여있는 형태로.

폼에 데이터가 있는 상태를 의미합니다.
해당 폼 인스턴스가, 데이터를 가지고 있다면, Django 는 해당 데이터를 검증하고, 데이터와 함께 HTML 로 렌더링 할수 있게 됩니다.


Unbound Form


만약에 폼이 unbound 되었다면, 해당 폼 인스턴스에는 데이터 검증 작업을 수행할수 없습니다 (검증할 데이터가 없기 때문입니다). 그렇지만, 비어있는 폼을 HTML 로 렌더 할수 있습니다.



폼 클래스로 폼 인스턴스 생성


하나의 unbound 폼 (데이터가 비어있는 폼 인스턴스) 을 생성하기 위해서는, 폼 클래스를 인스턴스화 시켜주면 됩니다.


1
f = ContactForm()

반대로, 폼에 데이터를 묶어주는, bound 폼 인스턴스를 생성하기 위해서는,


묶어줄 데이터를 사전 형태로 전달해주면 됩니다.



1
2
3
4
5
6
7
8
data = {
'subject': 'hello',
'message': 'Hi there',
'sender': 'foo@example.com',
'cc_myself': True
}

f = ContactForm(data)

이 사전안에 keys 는 필드 이름이고, 이는 Form 클래스안의 속성들과 대응합니다.


사전안에 있는 values 는 여러분들이 검증하려고 하는 데이터 입니다. 이들은 보통 문자열로 되어 있지만, 문자열이여만 하는 요구 조건은 없습니다. 전달될 데이터 타입은 필드 마다 다를수 있습니다.


is_bound


만약 여러분들이 form 인스턴스가 bound 인지 unbound 인지 실행시에 구분하고 싶다면, form 의 is_bound 속성의 값을 확인 하면 됩니다. True 혹은 False 를 반환합니다.


shell 에서 확인해보면,


1
2
3
4
5
6
7
In [3]: from forms_more_on_fields.forms import ContactForm                                                                                                             
In [4]: f = ContactForm()
In [5]: f.is_bound
Out[5]: False
In [6]: f = ContactForm({'subject': 'hello'})
In [7]: f.is_bound
Out[7]: True

  • 폼 인스턴스에 데이터가 들어가면, is_bound 를 호출했을때, True 를 반환하고
  • 폼 인스턴스에 데이터가 들어가지 않은 unbound 폼에 is_bound 를 호출하면, False 를 반환합니다

비어 있는 사전을 전달할 경우, 비어 있는 데이터를 가진 bound form 이 됩니다.


1
2
3
4
In [8]: f = ContactForm({})       # 비어있는 사전 전달                                                                                                                            

In [9]: f.is_bound
Out[9]: True

Bound Form 인스턴스를 가지고 있고, 어떻게든 데이터를 바꾸고 싶거나 혹은 unbound form 을 어떠한 데이터를 가지게 하고 싶다면, 또다른 Form 인스턴스를 생성하면 됩니다.


Form instance 안에 데이터를 변경하는 길은 없습니다. 한번 Form 인스턴스가 생성이 되면, 데이터를 가지고 있던 없던, 데이터는 변경이 불가능 합니다!


Reusable form templates


만약 여러분의 사이트가 공통된 렌더링 로직을 가진 폼들을 다수의 공간에서 사용한다면,


반복되는것을 폼의 템플릿 안에 저장하고 include 테그를 사용하여, 다른 템플릿 안에서 사용할수 있습니다.


1
2
3
4
5
6
7
8
9
{% include 'form_snippet.html' %}

# In form_snippet_html
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}


만약 폼 객체가 컨텍스트 안에 포함되어, 다른 이름을 가진 템플릿으로 전달 된다면, with 인자를 통해서, alias 설정을 할수 있습니다.


1
{% include "form_snippet.html" with form=common_form %}

Looping over hidden and visible fields


만약 여러분들이 수동으로 폼을 템플릿안에서 레이아웃을 잡는 작업을 하고 있다면, Django 의 기본 폼 레이아웃과는 반대되게, <input type="hidden"> 을 사용하여, 숨김처리가 되지 않은 필드들과 다르게 사용할수 있습니다.


예를들면, 숨겨진 필드들은 아무것도 출력하지 않기 때문에, 에러 메시지들을 해당 필드 옆에 출력 한다는것은 사용자들에게 혼란을 일으킬수 있을것입니다. 따라서, 이런 필드들의 에러들은 다른 방식으로 다루어 져야 합니다.


Django 는 숨겨진 필드와 노출된 필드들을 따로 반복할수 있게 해줍니다.


바로, hidden_fields() 와 visible_fields()


아래 예시를 참고합니다.



1
2
3
4
5
6
7
8
9
10
11
{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}

위의 예시는, 숨겨진 필드들 안에 있는 어떤 에러도 다루지 않습니다. 보통은, 숨겨진 필드안에 있는 에러는 폼 변조를 의미할수 있습니다. 보통 폼 동작은 폼을 바꾸지 않습니다.


Looping over the form’s fields


만약 여러분들이 각 폼 필드들을 위해 같은 HTML 테그들을 사용하고 있다면, 반복되는 코드들을 줄일수 있습니다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 반복문을 사용하여 반복되는 코드를 줄일수 있습니다 
# {% for %}

# 예시

{% for field in form %}
<div class="fieldwrapper">
{{ field.errors }}
{{ field.lable_tag }} {{ field }}
{% if field.help_text %}
<p class="help">
{{ field.help_text|safe }}
</p>
{% endif %}
</div>

{% endfor %}

반복문이 실행될때마다, 각 필드에서 사용할수 유용한 속성들이 존재 합니다.


1
2
3
4
5
6
7
8
# {{ field }} 가 포함하고 있는 유용한 속성들은 

# {{ field.lable }} 필드의 레이블을 표시합니다. 예) Email Address

# {{ field.label_tag }}
# 필드의 label 이 적절한 HTML <label> 태그로 감싸집니다. 이는 form 의 label_suffix 를 포함합니다. 예를들면, labe_suffix 의 기본값은 콜론입니다.

<lable for="id_email">Email address:</lable>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# {{ field.id_for_label }}
# 이 필드를 위해 사용될 ID (위 예시에서는 id_email).
# 만약 여러분들이 label 을 수동으로 만들고 있다면, 이것을 label_tag 대신에 사용할수 있습니다
# 이것또한 유용하게 사용될수 있습니다.
# 예를들면, 여러분들이 인라인 JavaScript 를 가지고 있고, 필드의 ID 를 하드코딩 하는것을 피하고
# 싶을때처럼 말이죠

# {{ field.value }}
# 필드의 값 예) someone@example.com

# {{ field.html_name }}
# 인풋 요소의 이름 필드에 사용될 필드의 이름, 설정 되어 있다면, 폼의 접두사를 고려합니다

# {{ field.help_text }}
# 필드와 관련된 hep text

# {{ field.errors }}
# 필드에 해당하는 유효성 혹은 검증 에러를 가지고 있는 <ul class-"errorlist">를 출력합니다
# 에러의 모습을 {% for error in field.errors %} 반복문을 사용하여, 커스터마이즈 할수 있습니다.
# 이 경우에는, 반복문안에 각 객체들은 에러 메시지를 포함하고 있는 문자열이 됩니다.

# {{ field.is_hidden }}
# 만약 필드가 숨겨진 필드라면 True 를 반환하고, 숨겨져 잇지 않다면 False 를 반환합니다
# 이것은 특출나게 템플릿 변수로써 유용하지 않습니다. 하지만 아래 예시같이 조건적인 테스트에서는
# 유용할수 있습니다

{% if field.is_hidden %}
{% endif %}

# {{ field.field }}
# 폼 클래스로부터 필드 인스턴스로 BoundField 로 감싸집니다.
# Field 속성들을 엑세스하기 위해 사용합니다. 예) {{char_field.field.max_length}}

Rendering form error messages


폼에 에러 메시지들을 출력해줄수 있습니다. 하지만, 물론 이 부분은 유연한 추가 작업일 뿐입니다.


현재까지 우리는, 폼 에러들을 어떻게 출력해주어야 하는지에 대해 걱정하지 않아도 되었었습니다.


이번 예시에서 우리는, 각 필드에서 발생하는 에러와 폼 전체에서 발생하는 에러에 대해서 어떻게 관리 해야 하는지에 대해서 다룹니다.


1
2
3
4
5
6
7
8
# {{ form.non_field_errors }} 가 폼의 가장 상단에 위치하고, 템플릿은 각 필드에 error 들을 조회 한다는것을 숙지 합니다 

# {{ form.필드명.errors }} 를 사용하면, 폼 에러의 리스트를 출력해 줍니다. 이는 순서가 정해지지 않은 unordered list 로 렌더 됩니다
아래와 같이 보여질수 있습니다.

<ul class="errorlist">
<li>Sender is required.</li>
</ul>

해당 리스트는 errorlist 의 CSS 클래스를 가지고, 모양을 스타일링 할수 있게 해줍니다. 만약, 여러분들이 조금 더 출력 된 에러들을 커스터마이즈 하고 싶다면, 반복문을 사용하여 이를 꾸며줄수 있습니다.



1
2
3
4
5
6
7
8
9
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}

</ol>

{% endif %}


필드 에러가 아닌것 (그리고 혹은, form.as_p) 를 사용하여, 폼의 상단에 렌더된 숨겨진 필드 에러들은 추가적인 nonfield 클래스와 함께 렌더가 됩니다.


이는, 특히 필드 특화된 에러들과의 구분을 도와줍니다. 예를들면,


1
2
3
<ul class="errorlist nonfield">
<li>Generic Validation error</li>
</ul>

The Forms API 를 확인하면, 에러들과, 스타일링 그리고 템플릿 안에서의 폼 속성들에 대한 것들을 확인 할수 있습니다.


Rendering Fields Manually


Django 가 forms.py 에 작성된 폼들을 템플릿에 자동으로 풀어놓게 하고 싶지 않으면, 수동으로 작업하는 방법도 있습니다.


각 필드들은, form.(폼필드명) 의 형태로, 해당폼의 속성으로 존재합니다. 그리고, Django 템플릿안에서 적절하게 사용하여 렌더 될수 있습니다.

예시를 들자면, 이전 포스팅에서 작성한 forms.py 와 views.py 를 기반으로 해서 예를 듭니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# forms.py 

from django import forms

class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_mysself = forms.BooleanField(required=False)

# views.py
def form_render(request):
form = ContactForm()
return render(request, 'form.html', {'form': form})

form.html 파일에 렌더를 수동으로 해주려면, 아래와 같이 작성해주면 됩니다.


더 읽어보기 »

Working with form templates


폼을 템플릿으로 가져오기 위해서 해야할 모든것은, 폼 인스턴스를 템플릿 컨텍스트에 넣어주는것입니다.



  1. 폼인스턴스 생성

    1
    2
    # views.py 에서 
    form = NameForm()
  2. 템플릿 컨텍스트에 넣기

    1
    return render(request, form.html, {'form': form})

템플릿 컨텍스트에 넣어진 컨텍스트 즉, {'form': form} 은, 해당 템플릿 페이지에서, 아래와 같이 사용될수 있습니다.


1
{{ form }}

이렇게 하면, 템플릿에서 적절하게 label 과 input 요소들을 렌더해줄수 있습니다.



Form rendering options


추가해야할 폼 템플릿 요소들

폼의 출력은 <form> 테그 혹은 폼의 제출 약식들을 포함하지 않는다는것을 잊지 마세요.

<form> 태그와 <submit> 태그 같은것들은 여러분들이 스스로 넣어줘야 합니다.


Django 에서 Form 을 템플릿에 렌더할때에, 옵션을 붙여서 폼의 출력 형태를 바꾸어 줄수 있습니다.


1
2
3
{{ form.as_table }} <tr> 테그로 감싸진 테이블로 폼을 렌더해줍니다 
{{ form.as_p }} <p> 테그로 감싸진 폼을 렌더해 줍니다
{{ form.as_ul }} <ul> 태그로 감싸진 폼을 렌더해 줍니다

form.as_table 과 form.as_ul 같은 경우, 상위 태그인 <table> 과, <ul> 요소들을 여러분들 스스로 작성하고 감싸주어야 합니다.



예제


아주 간단한 폼을 템플릿에 렌더해 보면,


더 읽어보기 »

Fields 에 대해서


이전 포스팅들에서 다루었었던 예시보다 좀더 유용한 폼을 한번 생각해 봅시다.


개인적인 웹사이트에 contact me 기능을 구현하는 폼을 생각해 봅시다. Contact Me 폼을 작성하기 위한 forms.py 파일은 아래와 같이 작성될수 있습니다.


1
2
3
4
5
6
7
8
from django import forms 


class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)

이전 포스팅에서 들었었던 폼의 예시는, 하나의 필드만 사용했었습니다. your_ name 과 CharField 만 사용햇었습니다.


하지만, 이번 경우에는, 4가지의 필드들을 가지고 있습니다.


Fields FieldTypes
subject CharField
message CharField(widget=forms.Textarea)
sender EmailField
cc_myself BooleanField


Widgets


각 폼의 필드는 그에 상응하는 Widget 클래스를 가지고 있습니다, 위의 예시에서는 widget=forms.Textarea 로 지정되어 <input type="text"> 같은 HTML 폼 widget 이 될것입니다.


대부분의 경우, 필드는 적당한 기본 widget 을 가지고 있을것입니다.


예를들면, 기본값으로 CharField 는 TextInput widget 을 가질것이고, 이는 <input type="text"> 를 HTML 안에서 만들어 내줍니다.


만약 <textarea> 가 필요했다면, 적절한 widget 을 Form 필드를 정의할때 지정해 주면 됩니다. 우리는 이것을 message 필드를 정의할때 지정해 주었습니다.



더 읽어보기 »

Django Form Classes


More about Django Form Classes


모든 폼 클래스들은

django.forms.Form 혹은 django.forms.ModelForm 클래스 둘중 하나의

서브 클래스들로 생성 됩니다.


ModelForm 은 Form.Form 그리고 ModelForm 의 서브클래스로. 사실상 공통 기능들을 BaseForm 클래스로부터 상속 받는다고 생각하면 됩니다.



Models and Forms

여러분드르이 폼이 직접적으로 Django 모델을 추가하거나 수정하는데에 쓰인다면,

ModelForm 이 시간과 노력 그리고 코드의 양을 줄이는데에 크게 기여할수 있습니다.

왜냐하면, ModelForm 은 Model 클래스로부터 적절한 필드들과 속성들을 가지고 폼을 생성해 주기 때문입니다.



Bound and Unbound Form instances


Bound 된 폼과, unbound 된 폼 사이의 차이점을 알아둡시다


Unbound Form

폼과 관련된 데이터를 가지고 있지 않은 폼을 의미 합니다.

사용자에게 폼이 렌더 되었을때, 해당 폼은 비어 있거나, 기본값들을 가지고 있을것입니다.


Bound Form

제출된 데이터를 가지고 있습니다.

따라서, 데이터가 유효한지 얘기하기 위해서 사용될수 있습니다.

만약, 유효하지 않은 bound form 이 렌더 된다면, 해당 폼은 인라인으로 에러 메시지들을 포함하여 사용자에게 어떤 데이터를 고쳐야 하는지 얘기해줄수 있습니다.



is_bound 속성


form 의 is_bound 속성은 해당 폼이 데이터를 가지고 있는지 없는지 확인해 줄수 있습니다.