웹 애플리케이션에서 회원가입이나 설문조사와 같은 사용자 입력을 처리할 때, 입력 값의 유효성을 검증하고 오류 메시지를 표시하는 것은 필수적입니다. Django의 Form과 ModelForm 컴포넌트는 이러한 작업을 자동화하여 개발 생산성을 크게 향상시킵니다.
Form 컴포넌트 기본 기능
Form 클래스 정의하기
Form 컴포넌트는 Django의 forms 모듈을 상속받아 정의합니다. ModelForm과 유사하게 각 필드의 데이터 타입과 제약 조건을 선언할 수 있습니다.
from django import forms
class UserRegistrationForm(forms.Form):
nickname = forms.CharField(max_length=10, min_length=3)
level = forms.IntegerField(min_value=1, max_value=99)
contact = forms.EmailField()
데이터 검증
폼 인스턴스에 데이터를 바인딩하면 is_valid() 메서드를 통해 유효성 검증을 수행할 수 있습니다.
form_instance = UserRegistrationForm({
"nickname": "devuser",
"level": 101,
"contact": "user@example.com"
})
# 모든 데이터가 유효한지 확인
form_instance.is_valid()
# 유효한 데이터만 추출
form_instance.cleaned_data # {'nickname': 'devuser', 'contact': 'user@example.com'}
# 오류 메시지 확인
form_instance.errors
is_valid()메서드 내부에서full_clean()함수가 실행되며, 이를 통해cleaned_data속성이 생성됩니다.
HTML 태그 자동 생성
폼 인스턴스를 템플릿에 전달하여 다양한 방식으로 입력 태그를 렌더링할 수 있습니다.
완전 자동 생성:
<form action="" method="post">
{{ form_instance.as_p }}
<input type="submit">
</form>
위 코드는 세 개의 p 태그로 감싸진 입력 필드를 생성합니다. as_ul과 as_table도 지원합니다.
수동 커스터마이징:
<form action="" method="post">
{% for field in form_instance %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
<input type="submit">
</form>
각 필드에 CSS 클래스나 사용자 정의 속성을 추가하려면 widget 파라미터를 활용합니다.
nickname = forms.CharField(
max_length=10,
min_length=3,
widget=forms.widgets.TextInput(attrs={'class': 'input-field', 'data-role': 'username'})
)
오류 메시지 출력
폼의 errors 속성을 템플릿에서 직접 사용할 수 있습니다.
<form action="" method="post" novalidate>
{% for field in form_instance %}
{{ field.label_tag }}
{{ field }}
{{ field.errors.0 }}
{% endfor %}
<input type="submit">
</form>
요청 처리 로직 예시
from django.shortcuts import render, HttpResponse
class UserRegistrationForm(forms.Form):
nickname = forms.CharField(max_length=10, min_length=3)
level = forms.IntegerField(min_value=1, max_value=99)
contact = forms.EmailField()
def register_view(request):
form = UserRegistrationForm()
if request.method == "POST":
form = UserRegistrationForm(request.POST)
if form.is_valid():
return HttpResponse('가입 완료')
return render(request, "registration.html", {"form": form})
request.POST는 딕셔너리 형태로 폼에 직접 전달할 수 있습니다. 불필요한 데이터는 자동으로 무시됩니다.novalidate속성을 사용하면 브라우저의 기본 검증을 비활성화할 수 있습니다. 서버 측 검증이 더 안전합니다.- GET과 POST 요청 모두 동일한
form변수명을 사용하여 템플릿 일관성을 유지합니다.
검증 방식 확장
필드 파라미터
기본적으로 Django가 제공하는 제약 조건을 필드에 직접 설정할 수 있습니다.
name = forms.CharField(max_length=10, min_length=3)
정규식 검증
from django.core.validators import RegexValidator
class ContactForm(forms.Form):
phone = forms.CharField(
validators=[
RegexValidator(r"\d+", "숫자만 입력 가능합니다"),
RegexValidator(r"^010-\d{4}-\d{4}$", "휴대폰 번호 형식이 아닙니다"),
]
)
훅(Hook) 함수
로컬 훅: 단일 필드 검증
def clean_nickname(self):
submitted_name = self.cleaned_data.get('nickname')
blacklist = ['admin', 'root']
if submitted_name in blacklist:
self.add_error('nickname', "사용할 수 없는 닉네임입니다")
return submitted_name
글로벌 훅: 여러 필드 간 관계 검증
def clean(self):
pwd = self.cleaned_data.get('password')
confirm_pwd = self.cleaned_data.get('confirm_password')
if pwd != confirm_pwd:
self.add_error('confirm_password', "비밀번호가 일치하지 않습니다")
return self.cleaned_data
Form 필드 주요 파라미터
| 파라미터 | 설명 | 비고 |
|---|---|---|
min_length |
문자열 최소 길이 | |
max_length |
문자열 최대 길이 | |
min_value |
숫자 최솟값 | |
max_value |
숫자 최댓값 | |
label |
필드 레이블 | 템플릿에서 {{ field.label_tag }}로 출력 |
error_messages |
사용자 정의 오류 메시지 | |
validators |
정규식 검증기 목록 | |
initial |
입력 필드의 기본값 | |
required |
필수 입력 여부 (기본 True) | False로 설정 시 선택 사항 |
widget |
HTML 태그 스타일 및 속성 |
error_messages 예시
nickname = forms.CharField(
max_length=10,
min_length=3,
error_messages={
'max_length': "닉네임이 너무 깁니다",
'min_length': "닉네임이 너무 짧습니다",
}
)
initial 예시
class LoginForm(forms.Form):
username = forms.CharField(
min_length=4,
label="사용자명",
initial="guest"
)
password = forms.CharField(min_length=6, label="비밀번호")
widget 예시
username = forms.CharField(
max_length=10,
min_length=3,
widget=forms.widgets.TextInput(attrs={'class': 'form-control', 'custom': 'value'})
)
주요 위젯 타입:
| 위젯 클래스 | HTML 태그 |
|---|---|
PasswordInput() |
비밀번호 입력 (input type="password") |
RadioSelect() |
라디오 버튼 (input type="radio") |
Select() |
단일 선택 드롭다운 (select) |
SelectMultiple() |
다중 선택 드롭다운 (select multiple) |
CheckboxInput() |
체크박스 (input type="checkbox") |
CheckboxSelectMultiple() |
다중 체크박스 |
ModelForm 컴포넌트
ModelForm을 사용하면 모델 정의를 기반으로 폼을 자동 생성할 수 있어 코드 중복을 줄일 수 있습니다.
from django import forms
from .models import Book
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = "__all__"
labels = {
"title": "도서명",
"price": "가격"
}
widgets = {
"password": forms.widgets.PasswordInput(attrs={"class": "secure-input"}),
}
Meta 클래스 속성
| 속성 | 설명 |
|---|---|
model |
참조할 모델 클래스 |
fields |
포함할 필드 ( "__all__" 또는 리스트) |
exclude |
제외할 필드 |
labels |
레이블 재정의 |
help_texts |
도움말 텍스트 |
widgets |
위젯 커스터마이징 |
error_messages |
오류 메시지 커스터마이징 |
ModelForm 검증
Form과 마찬가지로 is_valid() 또는 errors 접근 시 검증이 실행됩니다. 별도로 validators를 설정하지 않으면 모델 필드의 검증 규칙이 그대로 적용됩니다. 동일한 방식으로 로컬 및 글로벌 훅을 작성할 수 있습니다.
save() 메서드
ModelForm은 데이터베이스에 객체를 저장하는 save() 메서드를 제공합니다.
>>> from myapp.forms import BookForm
# 신규 객체 생성
>>> form = BookForm(request.POST)
>>> form.save()
# 기존 객체 업데이트
>>> existing_book = Book.objects.get(id=1)
>>> form = BookForm(request.POST, instance=existing_book)
>>> form.save()