Django의 Form 처리 과정

Hansu Kim·2021년 9월 29일
1

Django

목록 보기
7/10

Form은 HTML에서 적어도 한 개 이상의 type="submit"인 input 요소를 포함하는 <form>...</form> 태그 사이의 요소들의 집합으로 정의된다.

Form의 속성은 아래 두 가지로 구성된다.

  • action: Form이 submit될 때 처리가 필요한 데이터를 전달받는 곳의 자원/URL 주소. 미설정시 현재 페이지 URL로 다시 제출된다.
  • method : HTTP methond (POST / GET)

Sample Code

<form action="/team_name_url/" method="post">
    <label for="team_name">Enter name: </label>
    <input id="team_name" type="text" name="name_field" value="Default name for team.">
    <input type="submit" value="OK">
</form>
  • type : 어떤 종류의 위젯이 표시될지 정의
  • name/id : JavaScript/CSS/HTML에 있는 필드를 확인하는데 사용
  • value : 필드가 표시되는 초기값 정의
  • label : 사용자 인터페이스(UI) 요소의 라벨을 정의. for 속성에 다른 요소의 id를 입력하여 결합
  • submit : 모든 input 요소의 데이터가 서버로 업로드

Django의 Form 처리 과정

Django는 HTTP Request에 대해 아래와 같이 동적한다.
1. 뷰가 요청을 받고, 모델로 부터 데이터를 읽는 것을 포함한 요구된 동작을 수행한다.
2. 보여줄 데이터를 포함한 Context를 전달받은 템플릿으로부터 HTML Page를 생성하고 반환한다.
이 때, Django는 서버/사용자가 입력한 데이터를 처리 가능해야하며, 에러가 있으면 그 페이지를 다시 보여줄 필요가 있다.

아래 Diagram은 Django가 요청을 처리하는 플로우 차트다.

위 플로우 차트에서, Django Form이 주요하게 다루는 사항은 아래와 같다.

  1. 사용자가 처음으로 폼을 요청할 때 기본 폼을 보여준다.
  • 폼은 비어있거나 초기값으로 채워져있으며, 이렇게 유저가 입력한 값과 무관한 값을 unbound 상태라고 한다.
  1. 제출 요청으로 부터 데이타를 수집하고 그것을 폼에 결합한다.
  • 입력 데이터가 유효성을 위반한 경우, 에러메시지가 폼을 재표시
  1. 데이타를 다듬어서 유효성을 검증한다.
  • 사용자 입력을 정화(sanitisation) 하고 (공격성 문자를 제거 등) python에서 사용하는 타입의 데이타로 변환
  1. 입력된 어떤 데이타가 유효하지 않다면, 폼을 다시 표시한다.
  • 이 때, 표시값은 초기값이 아닌 유저 입력값과 에러 메시지
  1. 입력된 모든 데이타가 유효하다면, 요청된 동작을 수행한다.
  2. 일단 모든 작업이 완료되었다면, 사용자를 새로운 페이지로 보낸다.

Study Sample Code

동작 로직

1. Django는 login url을 urls.py에 따라 views.py의 login 함수 호출
2. login 함수는 forms.py의 LoginForm 인스턴스 생성
3. LoinForm 인스턴스는 forms.Form을 상속받은 클래스로, 필요한 폼 요소들이 forms의 값(?)을 상속받아 재정의한 변수형태로 선언되어있다.
4. views.py의 login 함수는 login.html 템플릿을 불러오고, LoginForm 인스턴스의 값을 사용하여 렌더링해 반환한다.

Model (forms.py)

class LoginForm(forms.Form):
    username = forms.CharField(
        error_messages={
            'required': '아이디를 입력해주세요.'
        },
        label="사용자 이름",
        max_length=32
    )
    password = forms.CharField(
        widget=forms.PasswordInput,
        label="비밀번호",
        error_messages={
            'required': '비밀번호를 입력해주세요.'
        }
    )

    # 기본적으로는 is_valid 를 통해 값이 들어있는지 아닌지가 검사되고 있으나,
    # 추가적으로 forms 안의 clean 함수를 상속하고 재정의하여 유효성 검사를 수행해준다.
    def clean(self):
        cleaned_data = super().clean()
        username = cleaned_data.get('username')
        password = cleaned_data.get('password')

        if username and password:
            fcuser = Fcuser.objects.get(username=username)
            if not check_password(password, fcuser.password):
                self.add_error('password', "비밀번호가 틀렸습니다")
            else:
                self.user_id = fcuser.id

Template (login.html)

{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
    <div class="col-12 text-center">
        <h1> 로그인 </h1>
    </div>
</div>
<div class="row mt-5">
    <div class="col-12">
        {{ error }}
    </div>
</div>
<div class="row mt-5">
    <div class="col-12">

        <form method="POST" action=".">
            {% csrf_token %}
            {% for field in form %}
            <div class="form-group">
                <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                <input type="{{ field.field.widget.input_type }}" class="form-control" id="" placeholder="{{ field.label }}" name="{{ field.name }}" />
            </div>
            {% if field.errors %}
            <span style="color: red">{{ field.errors }}</span>
            {% endif %}
            {% endfor %}
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
</div>
{% endblock %}

View (views.py)

from .forms import LoginForm

def login(request):
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            request.session['user'] = form.user_id
            return redirect('/')
    else:
        form = LoginForm()
    return render(request, 'login.html', {'form': form})

0개의 댓글