상세 컨텐츠

본문 제목

[Django] 폼(Form) 복습필요

Python/Django

by TUZA 2022. 9. 18. 00:29

본문

#질문 등록하기

 

질문을 등록하려면 먼저 “질문 등록하기” 버튼을 만들어야한다. 다음처럼 질문 목록 하단에 “질문 등록하기” 버튼을 생성하자.

#pybo/question_list.html
<a href="{% url 'pybo:question_create' %}" class="btn btn-primary">질문 등록하기</a>

#URL 맵핑

#pybo/urls.py

path('question/create/', views.question_create, name = 'question_create',)

#폼(Form)

흐름에 따라 question_create 함수를 작성해야한다. 하지만 뷰 함수를 작성하기 전에 폼(Form)에 대해 먼저 이해해보자.

폼은 쉽게 말해 페이지 요청 시 전달되는 파리미터를 쉽게 관리하기 위해 사용하는 클래스이다. 폼은 필수 파라미터의 값이 누락되지 않았는 지, 파라미터의 형식은 적절한 지 등을 검증할 목적으로 사용한다. 이 외에도 HTML 을 자동으로 생성하거나 폼에 연결된 모델을 이용하여 데이터를 저장하는 기능도 있다.

 

#pybo/forms.py

from django import forms
from pybo.models import Question


class QuestionForm(forms.ModelForm):
    class Meta:
        model = Question  # 사용할 모델
        fields = ['subject', 'content']  # QuestionForm에서 사용할 Question 모델의 속성

# QuestionForm 은 모델 폼(forms.ModelForm) 을 상속했다. 장고의 폼은 일반 폼(forms.Form) 과 모델 폼(forms.ModelForm)이 있는데
# 모델폼은 모델(Model)과 연결된 폼으로 폼을 저장하면 연결된 모델의 데이터를 저장할 수 있는 폼이다.
#모델 폼은 이너 클래스 인 Meta 클래스가 반드시 필요하다. Meta 클래스에는 사용할 모델과 모델의 속성을 적어줘야한다.

 

#템플릿

#templates/pybo/question_form.html
{% extends 'base.html' %}
{% block content %}
<div class="container">
    <h5 class="my-3 border-bottom pb-2">질문등록</h5>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }} # 자동으로 입력 폼을 만들어준다
        <button type="submit" class="btn btn-primary">저장하기</button>
    </form>
</div>
{% endblock %}

템플릿에서 사용한 {{form.as_p}} 의 form은 question_create 함수에서 전달한 QuestionForm의 객체이다. {{form.as_p}} 는 폼에 정의한 subject, content 속성에 해당하는 HTML 코드를 자동으로 생성한다.

보통 form 태그에는 항상 action 속성을 지정하여 submit 실행 시 action 에 정의된 URL 로 폼을 전송해야한다. 여기서는 특별하게 action 속성을 지정하지 않았다.

form 태그에 action 속성을 지정하지 않으면 현재 페이지의 URL 이 디폴트 action 으로 설정된다.

 

<form method="post" action="{% url 'pybo:question_create' %}">

하지만 이렇게 하면 question_form.html 템플릿은 “질문 등록” 에서만 사용 가능하다.

이후에 진행할 “질문 수정” 에서 이 템플릿을 활용할 수 없다.

왜냐하면 질문 수정일 경우에는 action 값을 달리해야하기 때문이다.

동일한 템플릿을 여러 기능에서 함께 사용할 경우에는 이처러 form의 action 속성을 비워두는 트릭을 사용한다.

 

#테이블에 데이터 저장하기

 

def question_create(request):
    if request.method == 'POST':
        form = QuestionForm(request.POST)
        if form.is_valid():
            question = form.save(commit=False)
            question.create_date = timezone.now()
            question.save()
            return redirect('pybo:index')
    else:
        form = QuestionForm()
    context = {'form': form}
    return render(request, 'pybo/question_form.html', context)



'''
URL 요청을 POST, GET 요청 방식에 따라 다르게 처리한다.
질문 목록 화면에서 "질문 등록하기" 버튼을 클릭한 경우에는
/pybo/question/create/ 페이지가 GET 방식으로 요청되어 question_create 함수가 실행된다.
왜냐하면 <a href="{% url 'pybo:question_create' %}" class="btn btn-primary">질문 등록하기</a>
와 같이 링크를 통해 페이지를 요청할 경우에는 무조건 GET 방식이 사용되기 때문이다.
따라서 이 경우에는 request.method 값이 GET 이 되어 if... else.. 구문에서 else 구문을 타게 되어 질문을 등록하는 화면을 렌더링한다.

그리고 질문 등록 화면에서 subject, content 항목에 값을 기입하고 "저장하기" 버튼을 누르면
이번에는 /pybo/question/create/ 페이지를 POST 방식으로 요청한다.
왜냐하면 앞서 설명했듯이 form 태그에 action 속성이 지정되어있지 않으면 현재 페이지가 디폴트 action 으로 설정되기 때문이다.

따라서 질문 등록 화면에서 "저장하기" 버튼을 클릭하면 question_create 함수가 실행되고
request.method 값은 POST 되어 다음 코드 블록이 실행될 것이다.


'''


if request.method == 'POST':
        form = QuestionForm(request.POST)
        if form.is_valid():  # 폼이 유효하다면
            question = form.save(commit=False)  # 임시 저장하여 question 객체를 리턴받는다.
            question.create_date = timezone.now()  # 실제 저장을 위해 작성일시를 설정한다.
            question.save()  # 데이터를 실제로 저장한다.
            return redirect('pybo:index')




'''
GET 방식에서 form = QuestionForm() 처럼 QuestionForm 을 인수 없이 생성했지만 
POST 방식에서는 form = QuestionForm(request.POST) 처럼 request.POST 를 인수로 생성했다.
request.POST 를 인수로 QuestionForm 을 생성할 경우에는 request.POST 에 담긴 subject, content 값이 
QuestionForm의 subject, content 속성에 자동으로 저장되기 때문이다.

request.POST 에는 화면에서 사용자가 입력한 내용들이 담겨있다.

그리고 form.is_valid() 는 form이 유효한지를 검사한다. 
만약 form에 저정된 subject, content 의 값이 올바르지 않다면 form에는 오류 메세지가 저장되고
form.is_valid()가 실패하여 다시 질문 등록 화면을 렌더링할 것이다.


form이 유효하다면 if form.is_valid(): 이후의 문장이 수행되어 질문 데이터가 생성된다. question = form.save(commit=False)는 form에 저장된 데이터로 Question 데이터를 저장하기 위한 코드이다. QuestionForm이 Question 모델과 연결된 모델 폼이기 때문에 이와 같이 사용할 수 있다. 
여기서 commit=False는 임시 저장을 의미한다. 즉, 실제 데이터는 아직 데이터베이스에 저장되지 않은 상태를 말한다. 여기서 form.save(commit=False) 대신 form.save()를 수행하면 Question 모델의 create_date에 값이 없다는 오류가 발생할 것이다. 왜냐하면 QuestionForm에는 현재 subject, content 속성만 정의되어 있고 create_date 속성은 없기 때문이다. 
이러한 이유로 임시 저장을 하여 question 객체를 리턴받고 create_date에 값을 설정한 후 question.save()로 실제 데이터를 저장하는 것이다.

'''
반응형

'Python > Django' 카테고리의 다른 글

[Django] 페이징  (1) 2022.09.22
[Django] 네비게이션바  (1) 2022.09.22
[Django] 스태틱(static) 디렉터리, 스타일시트 등록하기  (0) 2022.09.18
[Django] 데이터 저장 (복습필요)  (0) 2022.09.16
[Django] URL 별칭  (0) 2022.09.16

관련글 더보기