Form 에 대한 필요한 내역을 정리하다 보니 필요한 내역이 길어져서 포스팅의 순서를 아래와 같이 정리 해 보았다.
- Get / Post 이란?
- Form 의 전송 Flow
- Form
- Model Form
- Validators
1. Get / Post 이란?
Form 을 알기 전에 서버에서 호출 방법인 Get / Post 에 대해 먼저 알아야 한다.
참고 사이트 : https://www.w3schools.com/tags/ref_httpmethods.asp
- Get : 서버로부터 데이터 호출 시 URL뒤에 쿼리 스트링(Query String) 형태로 데이터를 전달하는 방식
- Post : Get 방식과는 달리 URL에는 표시 되지 않고 서버로 전송하는 메세지 안(Body)에 메세지를 담아 호출하는 방식
이 호출 방법들은 아래와 같은 특징 때문에 CRUD 중 Get 방식은 R을 Post방식은 CUD에서 사용 한다
GET | POST | |
Visibility | https://www.url.com/test?name1=value1&name2=value2 데이터는 URL에 표기 |
https://www.url.com/test URL에 데이터가 표시되지 않음 |
BACK button/Reload | 문제가 되지 않음 | 데이터 재 전송 됨 (브라우저는 데이터가 재 전송 예정임을 사용자에게 노티 필요) |
북마크 추가 | 북마크 가능 | 북마크 불가 |
캐시 가능 여부 | 캐시 가능 | 캐시 불가 |
브라우저 기록 | 파라미터가 브라우저 기록에 남음 | 브라우저 기록에 남지 않음 |
데이터 길이 제한 | 데이터를 URL에 추가하기에 URL 길이가 제한됨(최대 URL 길이는 2048자) | 제한 없음 |
데이터 유형에 대한 제한 사항 | ASCII 만 사용 가능 | 제한 없음 |
Encoding type | application/x-www-form-urlencoded | pplication/x-www-form-urlencoded 또는 multipart/form-data. 이진 데이터에 멀티파트 인코딩 사용 |
보안 | URL에 전송한 데이터가 포함됨. 때문에 비밀번호, 기타 민감한 정보를 보낼때 사용하면 안됨 |
매개변수가 브라우저 기록이나 웹 서버 로그에 저장되지 않기 때문에 POST는 GET보다 안전 |
Form 에서 전송하는 내역도 그 필요성에 따라 Get이나 Post 로 호출하면 된다.
<<!-- method 에 나와 있는 방식이 어떤 요청으로 보내겠다는 의미로
로그인 버튼을 누르면 form의 데이터를 post로 전송한다는 의미 -->>
<form method="post">
<button type="submit">로그인</button>
</form>
2. Form 의 전송 Flow
- 사용자가 서버에 Form 양식 요청 (Get 으로 Request)
- 서버가 사용자에게 Form 양식 전송 ( Response - Unbound Form)
- 사용자가 Form 에 데이터 입력후 Form 에 명시된 Method 방식으로 전송 (Post 로 Request)
- 서버에서 입력된 데이터를 Data와 Form 을 합쳐(Binding) Bound Form 생성
- 서버가 입력된 데이터가 유효한 데이터인지 체크하고 유효하지 않을 경우 사용자에게 유효한 데이터 재 요청
- 유효한 데이터가 들어올때까지 2~5번 반복
- 입력된 Form 이 유효하면 서버의 작업을 수행
- 작업이 모두 끝나면 새로운 Resonse 전송 (Ex.새 페이지 등)
3. Form
장고에서 Form 을 생성하려면 form, view, url, html 의 4가지가 작업되어야 한다
난 아래 순서대로 작업하였다.
본디 login 의 경우 django의 allauth 나 auth 에서 처리해주는 로직이 있어 아래 포스팅에서 불필요한 로직이 존재한다.
내 경우 포스팅에 쓸 수 없는 내역이 존재해서 가려서 작성한다.
3-1. forms.py
from django import forms
class LoginForm(forms.Form):
email = forms.EmailField(max_length=50, label ='이메일')
password = forms.CharField(max_length=12,widget=PasswordInput,required=True,label ='비밀번호')
portalid = forms.CharField(max_length=12, label = '포탈id')
form 에 해당하는 wiget 들에 대해 확인하고자 하면 아래 장고 사이트를 확인한다.
https://docs.djangoproject.com/en/3.2/ref/forms/fields/#built-in-field-classes
3-2. views.py
from .forms import LoginForm
def LoginView(request):
login_form = LoginForm()
return render(reqeust, 'login.html', {'form':login_form})
3-3. login.html
<form>
{{form.as_ul}}
<input type="submit" value = "전송">
</form>
as_ul, as_p, as_table 등은 모두 form 을 랜더링 하는 방식.
https://docs.djangoproject.com/en/2.2/ref/forms/api/#outputting-forms-as-html
3-4. urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path('/login/', views.LoginView, name='login'),
...
]
4. Model Form
model과 form 이 비슷한 form 을 따로 생성할 필요 없이 model 값을 그대로 받아와서 form을 생성한다.
html 과 url은 상단과 동일하게 사용가능
4-1. forms.py
class LoginForm(forms.ModelForm):
#사용할 모델을 작성
class Meta:
model = User
fields = ["email","password", "portalid"]
# 모든 필드 일 경우
# fields = '__all__'
4-2. views.py
내 경우 login 인시 변경되는 portal id값이 있어 함께 저장하도록 했다.
def LoginView(request):
if request.method == 'POST':
#바인딩
login_Form = LoginForm(request.POST)
#바운드 폼으로 모델 인스턴스 생성 > 모델 인스턴스를 처리 해줌
#데이터베이스에 저장 됨
user = login_form.save()
return redirect('index')
else:
login_Form = LoginForm()
return render(request, '/login.html', {'form': loginForm})
5. Validators
유효성 체크에 두가지 방법이 있다.
- Model 기반에 유효성 체크 방법
- 옵션인자를 사용하여 유효성 체크 로직을 추가하는 방법
5-1. Model 기반에 유효성 체크 방법
먼저, 모델 기반에 유효성 체크 하는 방법은 Model 내에 유효성을 체크로직을 삽입 하면 된다
model.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=50, blank=False, unique=True,
error_messages={'unique': '이미 있는 제목이네요!'})
content = models.TextField()
dt_created = models.DateTimeField(verbose_name="Date Created", auto_now_add=True)
dt_modified = models.DateTimeField(verbose_name="Date Modified", auto_now=True)
def __str__(self):
return self.title
max_length=50 : 해당 data의 최대 길이
blank=False : 해당 data를 빈칸으로 둬도 될지 (False - "" 값 허용 불가)
unique=True : 해당 data에 중복을 허용할지 (True- 중복 허용 불가)
error_messages : 문제가 터질경우 나타낼 메세지
- 'unique' 규칙의 유효성이 맞지 않을 경우 에러메세지 노출
- 'required' Form 필드의 기본 유효성 오류 메시지 변경시 작성 ex. {'required' : '비밀번호를 입력해 주세요'}
view.py
form.is_valid 를 사용하여 유효성 데이터를 체크 한다 반환값은 Boolean
def post_create(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
new_post = post_form.save()
return redirect('post-detail', post_id=new_post.id)
#get 방식
else:
post_form = PostForm()
return render(request, 'posts/post_form.html', {'form': post_form})
5-2. 옵션인자를 사용하여 유효성 체크 로직을 추가하는 방법
별도로 validators.py 를 생성하여 만들 경우 여러 필드에서 사용이 가능하다.
https://docs.djangoproject.com/en/3.2/ref/forms/fields/#built-in-field-classes
https://docs.djangoproject.com/en/2.2/ref/validators/
model.py
from django.db import models
from django.core.validators import MinLengthValidator
from .validators import validate_symbols
class Post(models.Model):
title = models.CharField(max_length=50, unique=True,
error_messages={'unique': '이미 있는 제목이네요!'})
content = models.TextField(validators =
[MinLengthValidator(10, '너무 짧군요! 10자 이상 적어주세요.'),
validate_symbols])
dt_created = models.DateTimeField(verbose_name="Date Created", auto_now_add=True)
dt_modified = models.DateTimeField(verbose_name="Date Modified", auto_now=True)
def __str__(self):
return self.title
validators.py
장고 내부에서 에러처리 중 인지하지 못한 건이 발생시 여기서 처리한다.
#유효성 검증 실패 건
from django.core.exceptions import ValidationError
def validate_symbols(value):
if('@' in value) or ('#' in value):
raise ValidationError('"@"와 "#"은 포함될 수 없습니다.')
forms.py
모든 Form class는 cleaned_data 를 가지고 있다.
cleaned_data 는 사용자가 입력한 데이터를 Dictionary 형태로 반환한다.
form 필드를 작성할때 사용한 유효성검증이 끝난 데이터가 들어가져 있으나, model을 사용한 경우 유효성 검증이 사용되어 있지 않다. 때문에 아래처럼 작성하여 처리할 수 있다.
from django import forms
from django.core.exceptions import ValidationError
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
def clean_title(self):
title = self.cleaned_data['title']
if '*' in title:
raise ValidationError('* 는 포함될 수 없습니다.')
return title
post.html
form의 커스텀 에러메세지 표기
{%extends './base.html' %}
{% load static %}
<form method="post">{% csrf_token %}
<h3>제목</h3>
<p>{{form.title}}</p>
{% for error in form.title.errors %}
<p>{{error}}</p>
{% endfor %}
<h3>내용</h3>
<p>{{form.content}}</p>
{% for error in form.content.errors %}
<p>{{error}}</p>
{% endfor %}
<input type="submit" value="전송"/>
</form>
'Python > Django' 카테고리의 다른 글
Django ORM과 QuerySet (0) | 2022.10.22 |
---|---|
Django - Bulk_create 로 대량의 데이터 DB에 insert하기 (0) | 2022.10.12 |
Django Model - Field 들 소개 (0) | 2022.10.07 |
우분투 내 MariaDB 설치 (0) | 2022.09.28 |
MariaDB 설치 시 오류 해결 방법 (ERROR 2002 (HY000)) (0) | 2022.09.27 |