/ DJANGO

(Django) Form과 ModelForm


로그인/회원가입을 개발할때 가장 먼저 폼을 위한 html을 작성하고 유저가 입력한 데이터의 유효성을 검증한다. 유효하지 않은 값을 사용자가 알 수 있도록 폼을 에러 메시지와 함께 다시 화면에 표시해준다. 이때 성공적으로 데이터가 제출되면 화면의 변환등으로 사용자가 입력에 성공했음을 알려주어야 한다. 이러한 과정을 일일히 작업해야 하는 번거로움을 줄여주는 기능이 바로 Form이다.

장고에서 제공해주는 프레임워크인 form은 이러한 과정을 단순화하고 자동화해준다고 생각하면 된다. 크게 3가지의 기능으로 나누어볼 수 있다

폼 생성에 필요한 데이터를 폼 클래스로 작성한다

폼 클래스에서 작성한 데이터를 가지고 HTML 폼을 만든다

유저가 입력한 데이터의 유효성 검증을 처리한다

Form을 사용할땐 순서를 정확히 알고 써야 덜 헷갈린다. 아래의 그림을 통해 순서를 익혀보자

form_img

회원가입을 예를 들어보겠다.

  1. (GET 요청일 경우)유저가 회원가입 페이지로 이동하면 회원가입 페이지는 화면에 필요한 데이터를 get요청 하게되고 url을 통해 해당 View의 get 메서드에서 form 클래스를 통해 html 폼을 화면에 그려준다
  2. (POST 요청일 경우)유저가 제공된 폼에 값을 입력해 제출하면 post요청으로 view의 post메서드에서 받은 데이터의 유효성 검증을 위해 form.cleaned_data를 통해 유효성 검증을 한다
  3. (입력값 유효성 검증 - invalid판정)값이 유효하지 않으면 invalid로 판정되고 form.errors를 통해 view에서 오류메시지를 리턴받는다. 해당 에러메시지는 context에 담겨 html 화면에 보여진다
  4. (입력값 유효성 검증 - valid판정)만약 값이 유효하다면 해당 값들을 저장하고 view에서 is_valid에 있는 로직들이 실행된다. 이곳에서 성공했을때의 url로 이동시킨다

Form과 ModelForm class 비교


Form 처리 과정

get메서드는 signup.html 템플릿에 form 레이아웃을 signinForm에서 작성한 필드를 가져와 화면에 그려준다

post 메서드는 유저가 유저가 form에 입력한 데이터를 view에서 form에 매개변수로 함께 보내면 form에서는 해당 입력값을 cleaned_data를 통해 유효성 검증을 한다 값들이 유효하면 valid 처리가 되어 view에 있는 is_valid의 로직이 실행된다. invalid처리가 되면 form에서 작성한 forms.ValidationError가 반환되어 에러 메시지가 view에 반환된다

# views.py

class SigninView(View):

    def get(self, request, *args, **kwargs):
        forms = SignupForm()
        context = {'forms':forms}
        return render(request, 'signin.html', context)
        
    def post(self, request, *args, **kwargs):
        signup_form = SignupForm(request.POST)
        if signup_form.is_valid():
            # 입력값 유효할때 작성하는 로직
            return redirect('/')
        
        error = singup_form.non_field_errors() # form에서 반환한 error
        context = {'error':error, 'is_errored':True}
            return render(request, 'signin.html', context)
        


위와 같이 forms.py에서 하는 역할을 따로 배정했기 때문에 view에서는 실제 비즈니스 로직들만 담을 수 있게 된다


# forms.py 

from django import forms
from user.models import User


class SigninForm(forms.Form):
	"""
	자신이 만들고 싶은 form에 자신이 넣고 싶은 데이터를 타입을 지켜 넣어준다. 
	아래에 작성한대로 form에 작성할 input이 생긴다
	"""	
    email = forms.CharField(
                lael='email', 
                max_length=30,
                widget=forms.TextInput(
                attrs={
                            'class': 'email',
                            'placholder':'email'
                }))
    
    email = forms.CharField(
                lael='password', 
                max_length=30,
                widget=forms.PasswordInput(
                attrs={
                            'class': 'password',
                            'placholder':'password'
                }))
			

    def clena(self):
        """
        유저의 입력값 유효성 검증, 폼에서 발생가능한 에러들을 처리
        """
        cleaned_data = super().clean()
        username = cleaned_data.get('email')
        password = cleaned_data.get('password')
        
        if username and password:
            user = User.objects.gget(username=username)
            if not user:
                raise forms.ValidationError('아이디가 존재하지 않아요')
		



장고 템플릿을 사용해 form 레이아웃을 그려준다 

입력폼 생성 : as_p(), as_table(), as_ul()

```python

{% extends 'base.html' %}

{% block content %}
<form method="post" action='{% url 'signin' %}'>
	{% csrf_token %}
	{{ forms.as_p }}
</form>
{% endblock content %}



ModelForm 처리과정

views / html은 Form에서 설명한 내용과 똑같은 로직으로 동작된다

ModelForm에서 fields는 꼭 작성해주어야 한다. 이 필드에는 model 클래스의 필드들중에서 폼에서 입력받고 싶은 필드를 지정하는 옵션이다.


# forms.py 

from django import forms
from user.models import User


class SigninForm(forms.ModelForm):
	"""
	자신이 만들고 싶은 form에 자신이 넣고 싶은 데이터를 fields에다 model을 기준으로
	작성해준다. widget이나 label을 원하는대로 변경이 가능하다
	"""	
    class Meta:
        model = User
        fields = ['email','password']
        widget = {
                'email': forms.EmailInput(attrs={'class': 'email'}),
                'password': forms.PasswordInput(attrs={'class':'pwd'}),
        labels = {
                'email':'이메일',
                'password': '내용',
        }}
    
    class Meta:
        model = User
        fields = ['email','password']
        widget = {
                'email': forms.EmailInput(attrs={'class': 'email'}),
                'password': forms.PasswordInput(attrs={'class':'pwd'}),
        labels = {
                'email':'이메일',
                'password': '내용',
        }}
			

    def clena(self):
        """
        유저의 입력값 유효성 검증, 폼에서 발생가능한 에러들을 처리
        """
        cleaned_data = super().clean()
        username = cleaned_data.get('usernmae')
        password = cleaned_data.get('password')
        
        if username and password:
            user = User.objects.gget(username=username)
            if not user:
                raise forms.ValidationError('아이디가 존재하지 않아요')
		



정리

  • Form은 모델에 쓰인 필드보다 추가적으로 다른 필드를 추가해야 할때 (ex) 회원가입 password-chk) , 즉 모델과 폼이 다를때 사용하면 편리하다

  • ModelForm은 모델에 쓰인 필드 그대로 form을 작성해야할때 사용하면 편리하다. 꼭 ModelForm이라고 모든 필드를 작성해야 하는 건 아니다. fields=[]에다 작성하고 싶은 필드의 네임을 작성하면 해당 필드가 form에 추가된다. 이때 form의 default값으로 들어간 widget이나 label을 변경할 수 있다