- 지금까지 사용자로부터 데이터를 제출 받기 위해 활용한 방법
- 그러나 비정상적 혹은 악의적인 요청을 필터링할 수 없음
- 유효한 데이터인지에 대한 확인이 필요함
유효성 검사
- 수집한 데이터가 정확하고 유효한지 확인하는 과정
- Django Form의 유효성 검사는 사용자가 입력한 데이터가 올바른 형식인지 자동으로 점검하는 기능을 제공한다.
- 예를 들어, 필수 입력 값이 비어 있거나 잘못된 이메일 형식을 입력하면 오류를 알려준다.
- 이 과정을 통해 서버에 잘못된 데이터가 저장되지 않도록 보호할 수 있다.
- 유효성 검사 구현의 어려움
- 유효성 검사를 구현하기 위해서는 입력 값, 형식, 중복, 범위, 보안 등 많은 것들을 고려해야 함
- 이런 과정과 기능을 직접 개발하는 것이 아닌 Django가 제공하는 Form을 사용
- 사용자 입력 데이터를 수집하고, 처리 및 유효성 검사를 수행하기 위한 도구
- 유효성 검사를 단순화하고 자동화할 수 있는 기능을 제공한다.
- 사용자가 잘못 입력한 데이터는 자동으로 오류로 처리되어 안전성을 높인다.
- 개발자는 이를 통해 빠르고 일관된 입력 검증 기능을 구현할 수 있다.
- Form Class 정의
- Form Class를 적용한 new logic
- view 함수 new 변경
def new(request):
form = ArticleForm()
context = {
'form': form,
}
return render(request, 'articles/new.html', context)
- new 페이지에서 form 인스턴스 출력
<h1>NEW</h1>
<form action="{% url 'articles:create' %}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
- 폼 필드를 화면에 표시하는 HTML 입력 요소를 정의하는 구성 요소
- HTML ‘input’ element의 표현을 담당
- Django Form의 widgets은 각 필드가 HTML에서 어떻게 렌더링 될지를 결정한다.
- 예를 들어, TextInput, Select, CheckboxInput 등 다양한 위젯 클래스를 사용해 입력 방식과 속성을 세부 조정할 수 있다.
- Widget 적용
- Form vs. ModelForm
- Form: 사용자 입력 데이터를 DB에 저장하지 않을 때 (ex. 검색, 로그인)
- ModelForm: 사용자 입력 데이터를 DB에 저장해야 할 때 (ex. 게시글 작성, 회원가입)
- Model과 연결된 Form을 자동으로 생성해주는 기능을 제공
- ModelForm은 Form 클래스와 Model 클래스를 결합한 형태로, 모델 필드를 기반으로 입력 폼을 자동 생성해준다.
- 데이터 수집과 저장 과정을 동시에 처리할 수 있도록 도와준다.
- ModelForm class 정의
- ModelForm의 정보를 작성하는 곳
- Meta class는 ModelForm 내부에서 어떤 모델과 연결할지, 어떤 필드를 사용할지 등을 정의하는 설정 공간이다.
- 폼의 동작 방식을 제어하는 핵심 역할을 한다.
- fields 및 exclude 속성
- Meta class 주의사항
- Django에서 ModelForm에 대한 추가 정보나 속성을 작성하는 클래스 구조를 Meta 클래스로 작성했을 뿐이며, 파이썬의 inner class와 같은 문법적인 관점으로 접근하지 말 것
from .forms import ArticleForm
def create(request):
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save()
return redirect('articles:detail', article.pk)
context = {
'form': form,
}
return render(request, 'articles/new.html', context)
is_valid(): 여러 유효성 검사를 실행하고, 데이터가 유효한지 여부를 Boolean으로 반환
- 제목 input에 공백을 입력 후 제출 시 에러 메시지 출력 확인 → 유효성 검사의 결과
- 공백 데이터가 유효하지 않은 이유와 에러메시지가 출력되는 과정
- 별도로 명시하지 않았지만 모델 필드에는 기본적으로 빈 값은 허용하지 않는 제약조건이 설정 되어있음
- 빈 값은
is_valid()에 의해 False로 평가되고 form 객체에는 그에 맞는 에러 메시지가 포함되어 다음 코드로 진행됨
- ModelForm을 적용한 edit 로직
- articles/views.py
def edit(request, pk):
article = Article.objects.get(pk=pk)
form = ArticleForm(instance=article)
context = {
'article': article,
'form': form,
}
return render(request, 'articles/edit.html', context)
- articles/edit.html
<h1>EDIT</h1>
<form action="{% url 'articles:update' article.pk %}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
- ModelForm을 적용한 update 로직
- articles/views.py
def update(request, pk):
article = Article.objects.get(pk=pk)
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
article = form.save()
return redirect('articles:detail', article.pk)
context = {
'article': article,
'form': form,
}
return render(request, 'articles/edit.html', context)
save 메서드
save(): 데이터베이스 객체를 만들고 저장하는 ModelForm의 인스턴스 메서드
- 폼 데이터가 유효한 경우, save() 메서드를 호출하면 모델 인스턴스를 생성하고 데이터베이스에 저장된다.
- instance 인자를 통해 새 객체 생성과 기존 객체 수정도 구분할 수 있다.
- 이 과정을 통해 코드 없이 손쉽게 DB 연동이 가능하다.
save() 메서드가 생성과 수정을 구분하는 법
- 키워드 인자 instance 여부를 통해 생성할 지, 수정할 지를 결정
HTTP 요청 다루기
View 함수 구조 변화
- new & create view 함수간 공통점과 차이점
- 공통점: 데이터 생성을 구현하기 위함
- 차이점: new는 GET method 요청만을, create는 POST method 요청만을 처리
- view 함수 구조화의 목적
- HTTP request method 차이점을 활용해 동일한 목적을 가지는 2개의 view 함수를 하나로 구조화
new & create 함수 결합
def create(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save()
return redirect('articles:detail', article.pk)
else:
form = ArticleForm()
context = {
'form': form,
}
return render(request, 'articles/new.html', context)
edit & update 함수 결합
def update(request):
article = Article.objects.get(pk=pk)
if request.method == 'POST':
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
form.save()
return redirect('articles:detail', article.pk)
else:
form = ArticleForm(instance=article)
context = {
'article': article,
'form': form,
}
return render(request, 'articles/update.html', context)