Web/Django

Django(장고)에서 POST 방식의 데이터 저장

daeunnniii 2021. 8. 3. 00:58
728x90
반응형

1. 템플릿에 답변 등록 폼 추가

앞서 작성해두었던 question_detail.html을 다음과 같이 수정해서 답변의 내용을 입력할 수 있는 텍스트창, 저장할 수 있는 "답변등록" 버튼을 추가해준다. 답변을 저장하기 위한 URL은 form 태그의 action 속성에  {% url 'pybo:answer_create' question.id %}로 지정해주었다.

 

form 태그 바로 밑에 {% csrf_token %}은 보안에 관련된 항목으로 form으로 전송한 데이터가 실제 웹 페이지에서 작성한 데이터인지 판단해주는 가늠자 역할을 한다. 만약 해커가 엉뚱한 방법으로 데이터를 전송할 경우에는 서버에서 발행한 csrf_token 값과 해당 툴에서 보낸 csrf_token 값이 일치하지 않기 때문에 오류가 발생할 것이다.

따라서 form 태그 바로 밑에 {% csrf_token %} 태그를 항상 위치시키도록 해야 한다!!

<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>

<form action="{% url 'notes:answer_create' question.id %}" method="post">
    {% csrf_token %}
    <textarea name="content" id="content" rows="15"></textarea>
    <input type="submit" value="답변등록">
</form>

**csrf_token 사용을 위해서는 CsrfViewMiddleware 미들웨어가 필요한데 이 미들웨어는 settings.py의 MIDDLEWARE 항목에 디폴트로 추가되어 있으므로 별도의 설정은 필요 없다.

 

2. URL 매핑

위 템플릿에서 {% url 'pybo:answer_create' question.id %}라는 URL을 지정해주었으니, urls.py에서도 해당 URL 매핑을 등록해주어야한다. notes/urls.py를 다음과 같이 수정해서 URL 매핑을 등록한다.

from django.urls import path
from . import views

app_name = 'notes'

urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('answer/create/<int:question_id>', views.answer_create, name='answer_create'),
]

이제 http://localhost:8000/notes/answer/create/1/, http://localhost:8000/notes/answer/create/2/ 와 같은 페이지를 요청하면 views.answer_create 함수가 호출된다.

 

3. answer_create 뷰함수

위 url을 요청했을 경우 호출될 함수를 이제 작성해주어야한다.

/notes/views.py에 answer_create 함수를 추가하고 다음과 같이 작성하자.

from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Question

###생략###

def answer_create(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    question.answer_set.create(content=request.POST.get('content'), create_date=timezone.now())
    return redirect('notes:detail', question_id=question.id)

question = get_object_or_404(Question, pk=question_id)은 이전 게시물에서도 설명했듯이, question_id 값을 통해 해당 데이터를 조회한다. 만약 해당 question_id가 존재하지 않으면 404 에러 페이지가 뜨도록 설정한다.

question.answer_set은 해당 질문에 대한 답변을 의미한다. Question과 Answer 모델은 외래키로 서로 연결되어있으므로 이와 같이 사용할 수 있다. question.answer_set.create은 해당 질문에 대한 답변을 생성한다.

request.POST.get('content')는 POST로 전송된 form 데이터 항목 중 content 값을 의미한다.

question.answer_set.create()가 어려우면 아래와 같이 작성해도 결과는 동일하다.

question.answer_set.create(content=request.POST.get('content'), create_date=timezone.now())

### == 동일 ###

answer = Answer(question=question, content=request.POST.get('content'), create_date=timezone.now())
answer.save()

마지막으로 답변을 생성한 후 다시 질문 상세 화면을 보여주기 위해 redirect 함수를 사용한다. redirect는 페이지 이동을 위한 함수이다. 그리고 detail 별칭은 question_id가 필요하므로 두번째 인수로 question.id를 전달한다.

 

4. 답변 저장

우선 답변을 입력해서 등록을 해보았다. 하지만 아직 답변을 등록한 내용을 볼 수 있는 코드를 작성하지 않았으므로 이 부분을 구현해야한다.

5. 답변 조회

작성한 답변을 질문 상세보기 화면에 표시하기 위해서 question_detail.html 템플릿을 아래와 같이 수정해준다. question.answer_set.count는 해당 질문에 대한 답변의 총 개수를 구해준다.

<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>
<br>
<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
    <ul>
        {% for answer in question.answer_set.all %}
        <li>{{ answer.content }}</li>
        {% endfor %}
    </ul>
</div>
<br>
<form action="{% url 'notes:answer_create' question.id %}" method="post">
    {% csrf_token %}
    <textarea name="content" id="content" rows="15"></textarea>
    <input type="submit" value="답변등록">
</form>

이제 이전에 등록한 답변들이 잘 출력되는 것을 볼 수 있다!

 

 

 

 

참고: https://wikidocs.net/73236

 

728x90
반응형