당신은 멋쟁이, 우리는 장고쟁이~

0%

The Template


이제 직접적으로 template 에 html 폼을 그려주기 위해서, name.html 파일을 생성해 줍니다.


지난 포스팅에서 views.py 에서 {'form': form} 이라는 컨텍스트를 name.html 파일로 전달하였으므로,



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import NameForm

def get_name(request):
# 만약 이것이 POST 요청이라면, 폼 데이터를 처리할 필요가 있습니다
if request.method == "POST":
# 폼 인스턴스를 생성하고, 요청으로부터 받아온 데이터로 채웁니다
form = Nameform(request.POST)
# 유효한 데이터인지 검사합니다
if form.is_valid():
# form.cleaned_data 안에 있는 데이터를 요구사항에 맞게 처리합니다.
# ...
# 새로운 URL 로 리다이렉트 시켜줍니다.
return HttpResponseRedirect('/thanks/')
# 만약 GET 이나 다른 method 의 요청을 받으면, 비어있는 폼을 생성합니다.
else:
form = NameForm()
return render(request, 'name.html', {'form': form})



템플릿에 있는 name.html 에서 아래와 같이 이라고 출력하면, 폼이 출력 됩니다.

1
2
3
4
5
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

더 읽어보기 »

The View


Django 웹사이트로 다시 전송된 폼 데이터는 뷰가 처리 합니다.


보편적으로, 폼을 발행했던 뷰가 처리합니다. 이는, 같은 로직들을 재사용하게 해줍니다.


폼을 다루기 위해서는,

뷰에서 폼을 발행하려고 하는 URL 을 위해 폼을 인스턴스화 시켜주어야 합니다.


Django 에서 폼을 다루려면, 폼을 출력할 URL 을 생각해놓고, 폼을 발행하기 전에, 폼을 인스턴스화 시켜주어야 한다는 이야기 입니다.



폼 인스턴스화 시켜주기



Django 프로젝트에서, buildingaform 이라는 앱을 따로 생성해주고

buildingaform 앱 안의 구조가 아래와 같다고 가정해 봅시다.


1
2
3
4
5
6
7
8
9
10
.
├── admin.py
├── apps.py
├── forms.py # 이전 포스팅에서 작성한 forms.py 파일
├── __init__.py
├── migrations
│   ├── __init__.py
├── models.py
├── tests.py
└── views.py # 전달된 폼데이터를 처리 혹은 폼을 인스턴스화

forms.py 파일이 생성되있는것을 확인할수 있고. views.py 가 전달된 폼 데이터를 처리 하거나, 폼을 인스턴스화 합니다.


views.py 파일을 간단하게 살펴보자면,



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.http import HttpResponseRedirect 
from django.shortcuts import render

from .forms import NameForm

def get_name(request):
if request.method == "POST":
# 요청이, POST 라면, form 인스턴스를 아래와 같이 생성해줍니다.
form = NameForm(request.POST)
# 유효한 데이터인지 검사하기 위해, is_valid 메서드를 사용해 줍니다.
if form.is_valid():
# form.cleaned_data 안에 있는 데이터를 요구사항에 맞게 처리할 로직을 작성합니다
# ..
# 새로운 URL 로 리다이렉트 시켜줍니다
return HttpResponseRedirect('/thanks/')
# 만약, GET 이나 다른 method 의 요청을 받으면, 비어있는 폼을 생성합니다
else:
form = NameForm()
return render(request, 'name.html', {'form': form})


Views.py 에서 폼을 처리하는 포인트


  • GET 요청으로 이 뷰에 요청이 들어오면

    해당 뷰는 비어있는 폼 인스턴스를 생성하고, 폼이 렌더될 템플릿 컨텍스트에 넣어놓습니다. 이것은, 우리가 처음 폼이 존재하는 URL 에 방문하였을때 예상할수 있는 일입니다. 비어있는 폼 인스턴스를 생성하였기 때문에, 비어있는 폼이 화면에 출력 됩니다.

  • POST 요청으로 사용자가 폼을 제출 하면

    해당 뷰는, 또다시 폼 인스턴스를 생성하는데, 요청으로부터 들어온 데이터를 채워줍니다 form=NameForm(request.POST). 이를 두고, 데이터를 폼에 묶어준다고 표현합니다.

  • is_valid() 메서드를 호출 합니다

    is_valid() 를 호출하였을때, True 가 반환되지 않는다면 (즉 False 가 반환될때), 폼과 함께 템플릿으로 다시 돌아갑니다. 이렇게 다시 폼이 출력되는 화면으로 돌아갈때에는, 비어 있는 폼이 아닐수 있습니다. 이전에 제출된 데이터로 채워져 있을것입니다. 따라서, 이전에 제출된 데이터들을 요구사항에 따라 수정 혹은 고쳐줄수 있습니다.

  • 만약 is_valid() 가 True 라면

    유효한 Form data 들을 cleaned_data 속성에서 찾을수 있을것입니다. 이 cleaned_data 속성 안에 드렁있는 데이터를 사용하여, 데이터베이스를 업데이트 하거나, 혹은 다른 처리과정을 HTTP redirect 를 하기전에 수행할수 있습니다.


The Form Class


우리는 이미 우리가 필요한 HTML 폼이 어떻게 보여질지 알고 있습니다.


1
2
3
4
5
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" values="OK">
</form>

해당 폼을 Django 에서 사용하기 위한 시작점은 아래와 같습니다.

앱 안에서 사용될 Django 폼을 만드려면,


forms.py


해당 앱안에 forms.py 파일을 만들어 줍니다. 그리고 아래와 같이 작성해 줍니다.


1
2
3
4
from django import forms 

class NameForm(forms.Form):
your_name = forms.CharField(label="Your name", max_length=100)

이 폼 클래스는, 하나의 필드 your_name 을 가진 하나의 폼 클래스를 정의합니다.


폼 클래스의 필드에서 우리는, 사람에게 친숙한 레이블을 필드에 적용해 주었씁니다 (이 경우에는, 우리가 지정한 label 의 경우 우리가 빠트렸어도 자동으로 생성되었을 것이긴 합니다)


필드의 최대 허용 길이는 max_length 로 정의 됩니다. 이것은 두가지 일을 합니다.


더 읽어보기 »

The work that needs to be done


여러분들이 사용자의 이름을 얻기위해 필요한 간단한 폼을, 웹사이트에 생성하고 싶다고 가정해 봅시다.

여러분들은 아마 아래와 같은 코드를, 여러분들의 템플릿 안에 필요로 할것 입니다.


1
2
3
4
5
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" values="OK">
</form>

위의 간단한 폼을 잠시 둘러보자면,


  1. 브라우저에게 POST 메서드를 사용하여, 폼 데이터를 /your-name/URL 에 반환하라고 얘기합니다
  2. Your name 으로 레이블 되고, OK 가 쓰여진 버튼을 출력합니다
  3. 만약에 template 에 전달된 context 에 current_name 이라는 변수를 가지고 있다면, your_name 필드를 미리 채우는데에 사용될것입니다.

위의 HTML 폼을 가지고 있는 템플릿을 렌더해줄 뷰가 필요할것 입니다. 그리고, 그 뷰는 current_name 필드를 적절하게 제공해줄수 있습니다.


폼이 제출될때


폼이 제출 될때에는, 폼 데이터를 가지고 있는 POST 요청이 서버에 보내집니다.


요청이 보내졌을때에, /your-name/ URL 과 상응하는 뷰도 필요할것입니다. 이 뷰는 적절한 키/값 페어들을 요청안에서 찾을것이고, 그것들을 처리해줄것 입니다.


정리


위의 예시는, 매우매우 간단한 폼입니다. 실전에서는, 하나의 폼이 10개 혹은 100개의 필드들을 가질수도 있고, 많은것들이 미리 채워져야 할 필요가 있을수 있습니다.


그렇지 않으면, 사용자가 몇번의 수정-제출 을 통해 폼의 동작이 결정될수 있습니다.


우리는 브라우저에서 어떠한 유효성 검사가 필요할지도 모릅니다. 심지어 폼이 제출되기 전에도 말이죠.


사용자들이 날짜를 달력에서 선택하는것 같이 아주 복잡한 필드들을 사용하길 원할지도 모릅니다.


일단, Django 가 이런것들을 위해 기본 작업을 하게 하는것이 훨씬 쉬운 길이 될수 있습니다. (직접 모든것을 구현하려면, 힘듭니다;)



Instantiating, processing and rendering forms


Django 에서 객체를 렌더링 해줄때 우리는 보통,


  1. view 에서 객체를 확보합니다 (예, 데이터베이스에서 가져오기)
  2. template 컨텍스트에 전달해 줍니다
  3. 템플릿 변수들을 사용하여, HTML 마크업으로 확장 시킵니다

템플릿에서 하나의 폼을 렌더링 해주는것은 다른 종류의 객체를 렌더링 해주는것과 거의 흡사 합니다.


하지만, 거기에는 몇가지 차이점들이 존재합니다.


  1. 데이터를 포함하고 있지 않은 모델 인스턴스일 경우에는, 우리가 그 인스턴스를 렌더링 해서 템플릿에서 어떠한 작업을 수행하려 할때, 유용하지 않을때가 많습니다. 하지만, 폼에서는 채워지지 않은 폼을 렌더 해주는것에 완벽한 의미가 있습니다 - 우리는 사용자가 비어있는 폼을 채워주길 바라며, 이것이 폼이 하고자 하는 일입니다
  2. 따라서, 우리가 뷰에서 모델 인스턴스를 다룰때에, 우리는 보통 데이터베이스에서 조회해 옵니다만, 폼을 다룰때에는, 뷰에서 폼을 인스턴스화 시켜주면 됩니다.

폼 인스턴스화


하나의 폼을 인스턴스화 할때에는, 우리는 폼을 비어있게 할것인지 혹은 미리 채워놓을것인지 선택할수 있습니다.


예를들면, 폼에 채울 데이터는 아래와 같습니다.



  • 저장된 모델 인스턴스에서부터 온 데이터
  • 다른 소스들에서 합친 데이터
  • 이전 HTML 폼 제출에서 받은 데이터

이전 HTML 폼 제출에서 받은 데이터가 흥미로운 부분인데, 이것은 사용자들이 단순히 웹사이트를 읽기만 하는것이 아니라, 정보를 역으로 보낼수 있게 해주기 때문에 흥미롭습니다.



Django Form Class


Forms in Django


우리는 HTML 폼에 대해서 간단히 설명 했습니다. 하지만, <form> HTML 태그는 단지 필요한 도구일뿐입니다.


웹 어플리케이션의 맥락에서,


form 은 HTML <form> 테그를 가르키거나,

혹은, 그것을 생성하는 Django Form,

또는, 제출되었을때 반환되는 구조화된 데이터

또는, 이 모든 부분들의 end-to-end 동작의 집합들이라고 말할수 있습니다.


Django Form Class


이 컴포넌트들의 시스템의 심장은 Django 의 Form Class 입니다.


매우 같은 방식으로, Django 모델이 객체의 구조, 동작 그리고 어떻게 표시가 되어야 하는지에 대해서 논리적인 묘사를 하듯이,


Form 클래스는 Form 을 묘사하고,

어떻게 작동하고 나타나야 하는지에 대해 결정합니다.



모델 클래스의 필드들이 데이터베이스 필드들을 가르키고 매핑되는것과 비슷하게도,


폼 클래스의 필드들은 HTML form <input> 요소와 매핑 됩니다 (ModelForm 은 모델 클래스의 필드들을 HTML form <input> 요소를 Form 을 통해서 매핑 합니다.)



폼의 필드들은 그들 스스로 클래스들입니다.

폼이 제출될때, 데이터를 관리하고 유효성 검사를 수행합니다.


DateField 와 FileField 는 매우 다른 종류의 데이터와 그 데이터 들과 같이 해야만 하는 다른 일들을 다룹니다.


폼 필드는 브라우저에서 사용자에게 HTML widget 으로 표시됩니다.

각 필드 타입들은 적절한 기본 widget class 들을 가지고 있지만, 필요할때에는 override 되서 사용될수 있습니다.

Django’s role in forms


폼을 다루는것은 복잡한 일입니다.


Django 의 어드민을 생각해보면,


서로 다른 종류의 데이터들의 많은 항목들이 폼안에 출력되도록 준비 되어야 하고,


HTML 로 렌더링 되어야하고, 편리한 인터페이스를 사용해서 편집되어야 하고, 서버로 반환되어야 하고, 유효성 검사와 정리가 되어야 하고, 그리고 나서도 추후 처리를 위해 저장 혹은 전달 되어야 합니다.


Django 의 form 기능은, 이 복잡한 일의 상당한 부분들을 간소화 시키고 자동화 시킵니다.


또한, Django 에서 폼은 대부분의 프로그래머들이 자신들이 코드를 작성한것만큼 안전하게 작동합니다.


Django Form 이 다루는 영역


  1. 데이터를 준비하고 재구조화 하여, 렌더할 준비
  2. 데이터를 위한 HTML 폼을 생성
  3. 클라이언트가 제출한 폼들과 데이터를 받는 부분
  4. 받은 데이터를 처리

이 모든것들을 수동으로 수행하는 코드를 작성하는것도 가능하지만,


django 는 여러분들을 위해 모든것들을 처리할 수 있습니다.


GET vs POST Method


GET 과 POST 는

Form 을 다룰때 쓸수 있는 유일한 HTTP Method 입니다.


Django 의 로그인 폼은 POST 메서드를 사용하여 반환 되고,


브라우저는 폼 데이터들을 모아서, 전송을 위한 인코딩을 합니다. 인코딩을 한뒤에 서버로 보낸다음 서버에서 응답을 받습니다.


GET


POST 와 비교했을때, GET 메서드는,


제출된 데이터를 문자열로 모으고,

모아진 문자열들을 URL 을 만들때 사용합니다.


URL 은 데이터가 전송되어야만하는 주소를 가지고 있고,

데이터 키 와 값을 가지고 있습니다.


GET 과 POST 의 다른 사용 목적


시스템의 상태를 바꾸기 위해서 사용되는 요청들 같은 경우,


예를들어, 데이터베이스에 어떠한 변경을 만들어주는 요청들은 POST 를 사용해야 합니다.


*POST 를 사용해야 할때 *

시스템의 상태를 바꾸기 위한 요청을 받을때,

예) 데이터베이스에 변경 사항들을 만들어주는 요청을 다룰때


GET을 사용해야 할때

GET 은 시스템의 상태에 영향을 주지 않는 요청을 처리할때만 사용되어야 합니다



GET 의 위험성


GET 메서드는, 폼에서 입력된 데이터를 받아서 URL 로 만들어 줍니다.


따라서, GET은 패스워드 폼 사용에는 적합하지 않습니다. 왜냐하면, 입력된 패스워드가 URL 에 보여지게 될것이기 때문입니다. 그리고, 브라우저 히스토리와 서버 로그에 순수 텍스트로 나타나게 될겁니다.


보안상 문제가 생기겠죠?



또한, 큰 데이터 양이나, 이미지 같은 이진수 데이터에도 적합하지 않습니다.


GET 요청을 어드민 폼에 사용하는 웹 어플리케이션은 보안상 아주 위험합니다.


공격자들은, 폼의 요청을 조작하여 시스템의 아주 민감한 부분에 접근할수 있습니다.

Django 의 CSRF protection 같은, 다른 보호 방법과 같이 쓰여지는 POST 의 경우, 공격자들의 접근을 좀더 관리 할수 있습니다.



GET 을 사용하면 좋을때


GET 을 사용하면 좋을때

GET Method 는, 웹 검색 폼 같은것에 사용하기 적합합니다

왜냐하면, GET 요청으로 표현되는 URL 들은 쉽게 북마크 될수도 있고,

쉽게 공유될수 있으면서, 쉽게 다시 제출될수 있습니다.


HTML FORMS


HTML 에서 form 은 <form></form> 안에 있는 요소들의 집합입니다.


이는 방문자들이 text 를 입력하고, 옵션을 선택하고, 객체들을 관리하고 혹은 제어하게 만들어 줍니다.


그리고 나서, 해당 정보를 다시 서버로 보내줄수도 있습니다.


이러한 몇가지 폼 인터페이스 요소들은 (예, text input, 혹은 checkboxes) HTML 자체에 내장 되어 있습니다만. 다른것들은 훨씬 더 복잡합니다. 예를들면, 보통 JavaScript 와 CSS 그리고 HTML 을 사용하여 날짜선택 팝업 혹은 슬라이더, 그리고 제어를 조종하는 <input> 요소들이 그렇습니다.



Form 이 지정해줘야할 2가지


form 은 대부분 아래 두가지를 지정해주어야 합니다.


  1. where? 사용자가 입력한 데이터가 어디로 반환 되어야 하는지
  2. how? 어떠한 HTTP Method 로 데이터가 반환 되어야 하는지

예시를 들자면, Django Admin 의 로그인 폼은 몇가지 아래의 <input> 요소들을 가지고 있습니다.


  1. username 을 위한 type="text" 라는 것이고,

  2. 다른 하나는, password 를 위한 input

  3. 마지막으로, 로그인을 진행하는 버튼을 위한 type=”submit” 을 가지고 있습니다.


그리고, 어드민에는 Django 가 입력값을 받은 다음에 무엇을 해야하는지 결정하기 위해, 사용자가 볼수 없는 숨겨진 텍스트 필드들도 존재합니다.


또한, 브라우저에 폼 데이터가 어떤 URL 로 보내져야 하는지, <form>의 action 속성에다가 URL 을 지정해 줍니다 /admin/. 그리고, 폼 데이터는, method 속성에 지정된 HTTP 동작을 통해서 보내집니다 (예, POST)


1
<input type="submit" value="Log in">

위 요소가 실행되면, 데이터는 /admin/ 에 반환됩니다.


Working with Forms


Django 의 Form에 대해 공식문서를 읽으면서 내용을 정리합니다.


Django 공식문서에서 Form 부분은,

web forms 에 대한 기본과, Django 에서 어떻게 Form 들이 다루어 지는지 소개합니다.


특정 부분에 대한 좀 더 자세한 디테일을 위해서는,

The Forms API, Form Fields 그리고 Form and field validation 문서들을 보면 자세히 알수 있습니다.


여러분들의 웹사이트와 어플리케이션이 단순히 컨텐츠만 발행하고, 방문자들한테서 input 을 받는 사이트가 아니라면, 여러분들은 form 에 대해 이해하고 사용할 필요가 없습니다.


하지만, 그 반대라면, 여러분들의 웹사이트와 어플리케이션은, 단순히 컨텐츠만 발행할 뿐만 아니라, 방문자들한테서 input 을 받고, 받은 input 을 기반으로 어떠한 작업을 실행해야 할지 모릅니다.


이러한 경우에는, form 에 대해서 이해하고 잘 사용할 필요가 있습니다.


Django 는 다양한 도구들과 라이브러리를 제공하여, 당신이 form 을 만들고 사이트 방문자로부터 값을 입력 받을수 있게 도와줍니다.


거기에, 입력값을 처리하고 값에 반응하는 작업을 할수도 있습니다.