Juhans
article thumbnail
Published 2022. 11. 19. 21:23
[Django] 장고 Form

HTML Form

장고의 Form 파일과 형식을 보기전에 HTML의 Form을 보자.

어떤 페이지에서 위와 같은 HTML Form이 나타나고 사용자가 form을 작성해서 submit을 하게 되면 Server는 Client의 정보를 받게 된다.

 

이때 Client가 Server에게 요청정보를 보낼 때 보낼 수 있는 방식이 여러가지가 존재하는데 그 중에서 GET과 POST를 먼저 살펴보자.

 

GET

위에서 HTML로 만든 Form을 사용자가 작성해서 GET방식으로 요청정보를 Server에게 넘겨줬다고 가정해보자. 요청정보를 받는 방식이 GET이기 때문에 아이디/비밀번호/성별 등등의 정보가 URI에 담겨 보내지게 된다.

 

URL/URI에 담겨지는 방식은 아래와 같다.

Client가 보내는 요청정보는 위 처럼 HeaderBody로 나뉘어질 수 있다. 사실 Header에는 보통 공개적으로 보여지고 처리되는 데이터가 들어가게 되고 Body에는 Server가 요청정보를 받았을 때 확인할 수 있는 비공개적인 데이터가 들어가게 된다. 

 

GET방식에서는 요청정보의 Header에 정보가 들어가기 때문에 보통 쿼리스트링으로 URI에 정보를 담게된다. 이런 URI는 정보를 담을 수 있는 공간이 제한적이기 때문에 대용량데이터는 전송할 때 부적절하며, password(위 예시에서 pwd)같은 비공개적으로 전달해야하는 정보가 공개된다는 문제가 있다. 때문에 공개가능하고 간단하며 용량이 작은 데이터를 요청할 때는 GET방식도 괜찮지만 그렇지 않은 형식의 데이터에 대해서는 적절하지 않을 수 있다.

 

GET방식의 쿼리스트링은 name과 value의 쌍으로 들어가게된다. 위의 예시 URI처럼  'name=value&name2=value2%...' 형식을 띄고 URL뒤 '?'뒤부터 나열하면 된다.

 

POST

POST는 GET방식과 다르게 URL에 정보가 노출되지 않고 Body에 쿼리스트링(질의문자열)을 담아 보내기 때문에 용량의 제한이 없다. GET방식처럼 URL에 정보가 노출되지는 않지만 개발자도구를 통해 찾아보면 보내는 body 정보가 나타날 수도 있기 때문에 암호화하는 것을 추천한다고 한다.


HTML의 Form에서는 method라는 인자로 어떤 방식으로 form을 submit할 것인지 정할 수 있다.

 

+ form에서 파일을 업로드하는 input이 있을 때는 반드시 form에 ' enctype="multipart/form-data" ' 옵션을 넣어줘야한다!

 

CSRF

CSRF는 사이트간 요청 위조를 말한다. CSRF는 이전에 해당 사이트에 접근하지 않았던 임의의 유저가 갑자기 POST방식을 통해 비정상적인 접근을 하는것을 말한다. 

이런 비정상적인 접근을 막기위해 Server에서는 CSRF 토큰이라는 것을 발급해주는 CSRF middleware라는 것이 존재한다. 이 CSRF middleware는 GET으로 어떤 페이지에 요청을 한 사용자에게 CSRF 토큰을 발급하고 그 페이지에 방문했던 사용자가 POST요청을 할 때 발급해주었던 CSRF 토큰을 확인해서 비정상적인 접근 자체를 막는다.

CSRF 토큰 Flow

실제 장고에서는 Middleware에 포함되어 GET이 아닌 직접적으로 어떤 URL에 POST방식으로 요청이 들어오면 403 Error를 내뱉도록 하고 있다.

 

HTML에서의 CSRF Token

POST방식의 Form에서 만약 CSRF 토큰을 보내주지 않으면 위에서 말한 것 처럼 403 Error가 발생하게 된다. 때문에 HTML에서 장고 문법으로 CSRF token을 Server에 보내주는 과정을 명시해야한다.

위 코드는 Blog에 Post를 등록하는 Form Class로 간단하게 구현한 페이지의 HTML이다. form 태그 바로 밑에 csrf_token이라는 장고 태그가 눈에 보인다. 저 부분을 명시해줘야 에러를 피하면서 Server에 POST 요청을 할 수 있다.

 

HttpRequest

HttpRequest는 웹으로 전송하는 요청정보로 Client가 Server쪽에 보내는 정보이다. 반대로 HttpResponse는 Server가 Client에 보내는 응답정보이다.

위 값들은 HttpRequest가 가지는 속성들이다.

 

각 속성들은 GET, POST 요청 방식에 따라 다른 값이 들어갈 수 있다.

예를 들어, 위와 같은 view함수가 POST 요청방식의 form을 웹 페이지에 띄워 각 속성들의 값을 받는다면,  request.POST에는 쿼리스트링이 들어있으며 POST 요청 방식이기 때문에 body안에 있는 쿼리스트링이 추출된다. 

 

반대로 get으로 요청하면 GET도 쿼리스트링 형태로 가지지만 요청정보의 header에 위치하고 있을 것이다.

 

→ POST, GET 둘 다 QueryDict에 담겨져 있다.

 

HttpRequest.Files는 POST 방식으로 Client가 Server에 요청할 때 넘겨주는 file이다. 실제 저장공간은 'media'에 위치하고 있지만 파일의 이름과 형식은 MultiValueDict에 담겨져 있다.

HttpRequest 응용

HttpRequest의 속성들을 활용해서 여러가지 웹 기능을 구현할 수 있다.

Blog 앱 검색 기능

Form에서 인자들과 함께 GET 방식으로 Server에 요청을 하면 HttpRequest 형식으로 정보들이 백엔드 쪽으로 넘어간다. 

이런 특성을 사용해서 Blog model에 존재하는 instance를 검색하는 기능을 구현해보자.

blog app 내부 urls.py
Blog 인스턴스 검색 구현(list.html)

HTML에서 위와 같이 form을 구성했다면 input 부분에서 text를 받아와 keyword라는 이름으로 HttpRequest에 담겨 전달된다. 

view 함수

View 함수를 확인해보면 keyword라는 인자를 get 하는데, 이때, 위 HTML Form내부 input text가 웹에서 입력되면 search_key라는 변수에 이 text가 들어가게 되는 것이다. 이후 Post.objects.all() 을 통해 모든 post instance를 QuerySet 형태로 가져오고 search_key가 존재한다면 filter와 contains를 통해서 해당되는 post instance를 찾는다.

 

여기서 끝이 아니고 render라는 웹페이지를 불러오는 함수를 통해 다시 blog/list.html을 부르고 이때 filtering을 통해 찾았던 post instance들을 출력한다.

 

만약 검색을 하지 않았거나 list.html 페이지에 처음 접근했다면 search_key에는 아무것도 없기 때문에 모든 instance들, Post.objects.all()의 전체 결과가 표시된다.


장고 Form

장고 Form은 GET과 POST일 때 방식이 다른데 그 순서는 아래와 같다.

 

HTML Form을 사용하는 방식

  1. GET 방식의 입력 페이지 응답을 위한 구현
    1. <form>태그를 사용하여 입력 폼을 작성한다.
  2. POST 방식의 서비스 처리 응답을 위한 구현
    1. 사용자가 입력한 값들을 추출한다.
    2. 사용자가 입력한 값들이 올바른 값인지 유효성을 검사한다.
    3. 유효성 검사에 실패하면 오류 메시지와 함께 입력 페이지를 응답한다.
    4. 유효성 검사에 성공하면 사용자 입력값들을 서비스 처리한다.

Django Form을 사용하는 방식

  1. GET 방식의 입력 페이지 응답을 위한 구현
    1. 장고 Form 클래스를 선언하고 필드 속성으로 입력 Form을 처리한다.
  2. POST 방식의 서비스 처리 응답을 위한 구현
    1. HttpRequest.POST값을 장고 Form 객체에 바인딩한다.
    2. 장고 Form의 is_valid 메소드를 호출하여 유효성을 검사한다.
    3. 장고 Form은 is_valid() 반환값이 False이면 유효성 검사 실패로 판 단하여 오류 메시지와 함께 입력 페이지를 응답한다.
    4. 장고 Form은 is_valid() 반환값이 True이면 유효성 검사 성공으로 판 단하고 유효성 검사에 성공한 입력값들을 cleaned_data 변수에 저 장한다. cleaned_data를 기반으로 서비스 처리를 진행한다.

 

HTML Form을 사용하는 방식에서는 HTML에서 직접 Form을 구성해줘야한다. 또한 유효성 검사도 수행될 수 있도록 설정해줘야한다. 하지만 장고 Form 클래스를 이용하면 Model을 참고해서 Form을 알아서 만들어줄 수도 있고 유효성 검사도 Form 클래스 내부적으로 진행되기 때문에 작업자가 따로 진행하지 않아도 된다. 

 

(하지만 결국 HTML에 Form을 나타내는 것은 동일함.)

 

Form 사용방식

blog/forms.py

위의 form 클래스 정의를 보면 마치 model을 정의하는 것처럼 Field를 정의하고, 또, 어떤 model을 참고해서 form을 만들 때 내부 Meta 클래스를 정의해서 받아들일 수 있는 field만을 참조할 수도 있다. (model을 참조하면 일일이 field를 정의해주지 않아도 되어서 간편하다!)

 

  1. Form을 정의한다. (직접 field 정의해도 되고 model을 참조해서 정의해도됨)
  2. 정의한 Form 클래스를 View함수에서 객체로 선언하고 form이 있는 HTML에 context로 넘긴다.
  3. form의 간단한 표시기능(as_table같은 메서드)을 통해 HTML에서 표시! → Form 완성

Form Field → Form 태그 변환

Form Field를 HTML Form 태그로 변환해주는 메소드는 다음 세가지 종류가 있다.

  • as_p() : HTML Form 태그를 <p> 태그로 분리한다. (paragraph 단위로 분할)
  • as_ul() : HTML Form 태그를 <li> 태그로 분리한다. (리스트 단위로 분할)
  • as_table() : HTML Form 태그를 <tr> 태그로 분리한다. (table 형식으로 form 구성)

 


Form Field 종류

form field 종류

Form Field의 종류이다. 대부분 model에도 있는 Field로 보인다. 

 

정상적으로 post Form이 만들어진 것을 확인할 수 있다.

post_create View함수를 사용해서 링크에 접속하면 GET방식으로 Form이 들어있는 HTML을 불러오고 이 Form을 사용자가 작성해서 '등록' 버튼을 누르면 POST 방식으로 다시 post_create View함수가 실행되면서 form.is_valid() 유효성검사, **form.cleaned_data (key, value 쌍의 form에서 작성했던 데이터)를 넣어 새로운 인스턴스를 생성한다.

views.py/post_create 함수

이렇게 생성해도 되지만 아래처럼 form.save() 메서드를 사용해서 바로 form에 입력된 데이터를 저장해줘도 된다. 이것이 form을 사용하기 때문에 가능한 장점이다. (form이 model을 참조하고 있기 때문)

views.py/post_create 함수


Reference

https://hongsii.github.io/2017/08/02/what-is-the-difference-get-and-post/

 

GET과 POST의 차이

HTTP HTTP는 웹상에서 클라이언트와 서버 간에 요청/응답으로 데이터를 주고 받을 수 있는 프로토콜입니다. 클라이언트가 HTTP 프로토콜을 통해 서버에게 요청을 보내면 서버는 요청에 맞는 응답을

hongsii.github.io

https://eunjin3786.tistory.com/133

 

[Django] HTTP Request를 받아서 응답해주기 (GET, POST, PUT, DELETE)

이 포스팅은 총 2단계로 이루어집니다. 👉 1단계 : HTTP Request를 잘받는 지 확인 + GET 요청에는 더미 JSON 주기👉 2단계 : 실제 HTTP Method 동작을 하며 데이터를 건들이기 1단계 장고의 View 는 아래의 H

eunjin3786.tistory.com

 

'' 카테고리의 다른 글

[Django] 장고 View  (0) 2022.11.21
[Django] URL Reverse  (0) 2022.11.19
[Django] 장고 ORM  (2) 2022.11.19
[Django] 장고 Model 활용  (1) 2022.11.19
[Django] Template 템플릿  (0) 2022.11.15