#13 데이터 저장 2
1. 질문 등록
지금까지 만든 웹사이트는 질문 리스트와 각 질문의 상세내용을 볼 수 있고 각 질문에 대해 답변도 등록할 수 있는
기능을 갖추었다. 이제 질문을 등록할 수 있다면 최소한의 기능을 갖춘 게시판이 완성될 것이다.
먼저 질문등록을 하려면 등록 버튼을 만들어야한다. question_list.html 을 다음과 같이 수정하여 질문 리스트 페이지
하단에 질문 등록 버튼을 생성하자.
다음으로 별칭 pybo:question_create 에 해당하는 url 매핑을 추가해야한다. pybo/urls.py 를 다음과 같이 수정한다.
2. 폼(Form)
이제 뷰에서 실제로 question_create 함수를 정의해야하는데, 그에 앞서 먼저 폼(form)에 대해 알아보자.
폼(form)은 웹 페이지 요청시 전달되는 파라미터들을 쉽게 관리하기 위해 사용하는 클래스로, 필수 파라미터들이
누락되지 않았는지, 형식이 적절한지 등을 검증할 수 있으며 HTML을 자동생성하거나 폼에 연결된 모델을 이용하여
데이터를 저장할 수도 있다. 아래 코드는 pybo/forms.py 에 질문 등록에 사용될 QuestionForm 을 구현한 것이다.
장고에서 사용되는 폼은 일반 폼(forms.Form) 과 모델 폼(forms.ModelForm) 두 종류로 나뉜다. 모델 폼의 경우 모델과
연결된 폼으로, 연결된 모델의 데이터를 저장할 수 있다. 모델 폼은 이너 클래스인 Meta 클래스를 반드시 필요로한다.
Meta 클래스에는 연결할 모델과 모델의 속성을 적어야 한다.
QuestionForm 은 Question 모델과 연결되는 모델 폼이며, 필드값으로 subject(제목)와 content(내용)가 있다.
labels 는 각 필드값에 대해 간단히 설명하는 텍스트를 넣어둔 것이다.
3. 뷰 함수 생성
폼을 만들었으니 이제 pybo/views.py 에 다음과 같이 question_create 함수를 작성한다.
forms.py의 QuestionForm 을 import 한 뒤 폼의 인스턴스를 생성, pybo/question_form.html 템플릿에 질문 등록에
사용될 폼으로 넘겨주어 렌더링한다.
4. 템플릿
이제 질문 등록을 위한 템플릿 templates/pybo/question_form.html을 작성해야한다. {{ form.as_p }} 코드로 폼에
정의한 속성들을 입력받는 HTML 코드를 자동으로 생성할 수도 있지만 이 방식은 디자인 측면에서 한계가 명확하고
디자인 영역과 서버 개발 영역이 분리되지 않는다는 문제가 발생한다. 여기서는 수동으로 폼을 작성하는 내용만을
다루기로 한다.
다음과 같이 질문 등록 템플릿 pybo/question_form.html을 작성한다.
다른 템플릿과 마찬가지로 base.html을 상속하여 content 블록을 구현한다. 절차는 다음과 같다.
① 요청 방식이 post인 form 엘리먼트를 생성하고 답변 등록을 구현할 때 했던 것 처럼 보안을 위해 {% csrf_token %}
을 최상단에 위치시킨다.
② {% if form.errors %} 블록으로 전달된 폼이 올바른 상태가 아니라면 경고문을 출력하도록 한다.
③ from-group 클래스로 제목과 내용을 입력받는 html 코드를 작성한다.
④ 폼을 제출할 submit 타입의 버튼을 생성한다.
5. 뷰 함수 완성
여기까지의 작업만으로는 질문 등록 페이지에서 아무리 내용을 입력하고 save 버튼을 눌러도 아무 동작도 일어나지
않을 것이다. 뷰 함수에 데이터를 저장하는 코드를 작성하지 않았기 때문이다.
pybo/views.py 의 question_create 함수를 다음과 같이 수정한다.
question_create 함수가 호출되는 경우는 처음 질문 등록 버튼을 눌렀을 때와 질문 등록 폼을 완성하고 제출했을 때의
두 가지 경우로 나뉜다. 두 경우는 데이터 전송방식(get or post)으로 구분하며, 전자의 경우 빈 QuestionForm 을
생성하여 question_form.html 로 전달하며 후자의 경우, 폼이 정상적으로 제출되었다면 데이터를 저장한 뒤 질문 리스트
페이지로 리다이렉트, 폼이 비정상적인 상태라면 질문 등록 페이지로 되돌아간다.
※ question = form.save(commit=False) 에서 commit을 False로 지정한 이유는 폼으로 생성된 question 인스턴스가
아직 create_date 데이터를 담고있지 않기 때문이다. 우선 인스턴스를 생성한 뒤 create_date를 설정해주고 나서야
save를 실행하여 실제로 데이터를 저장하는 것이다.
6. 답변 등록
이전에 미리 구현해두었던 답변 등록 또한 폼을 적용하여 다시 구현해보자.
먼저 답변 등록에 사용할 폼을 forms.py 에 다음과 같이 정의한다.
답변의 경우 제목이 없기 때문에 내용 필드 하나만을 가진다.
다음으로 views.py 의 answer_create함수를 다음과 같이 수정한다.
answer_create 함수의 경우 POST 방식으로만 호출되기 때문에 else 문의 부분은 필요가 없지만 구조의 통일을
위해서 위와 같이 작성한다.
마지막으로 필수 항목이 누락된 경우 에러메시지를 표시하기 위해 question_detail.html 의 답변 등록 부분에
다음과 같이 에러 표현 부분을 추가한다.
{% if form.errors %} 아래로 에러 표시용 코드를 삽입한 것을 확인할 수 있다.
7. 테스트
여기까치 작업을 마쳤다면 이제 질문과 답변의 등록/조회가 모두 가능하게 되었다.
① 질문 리스트
등록된 질문의 리스트가 정상적으로 표시되며 하단에 질문 등록을 위한 버튼도 확인할 수 있다.
② 질문 등록
질문 등록 버튼을 클릭하면 질문 등록을 위한 페이지로 연결된다.
제목이나 내용이 누락된 경우 에러메시지를 표시한다.
정상적으로 제목과 내용을 입력한 뒤 save를 누르면 정상적으로 질문이 등록되어 리스트에 표시되는 것을 볼 수 있다.
③ 질문 상세 조회
리스트에서 질문을 클릭할 경우 질문의 내용을 확인할 수 있으며 질문에 대한 답변 또한 작성할 수 있다.
④ 답변 작성
답변 내용을 누락한 경우 에러 메시지를 표시한다.
정상적으로 답변 내용을 입력할 경우 답변이 등록되어 정상적으로 조회되는 것을 볼 수 있다.