Django - 데이터 저장
● 데이터 저장
- 답변 등록 폼
[파일명: projects\mysite\templates\pybo\question_detail.html]
<h1>{{ question.content }}</h1>
<div>
{{ question.content }}
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token%}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변등록">
</form>
** {% csrf_token %}은 보안에 관련된 항목으로 form으로 전송한 데이터가
실제 웹 페이지에서 작성한 데이터인지를 판단하는 가늠자 역할
** form 태그 바로 밑에 {% csrf_token %} 태그를 항상 위치 // 없을 시 오류 발생
※ CSRF란?
CSRF(cross site request forgery)는 웹 사이트 취약점 공격을 방지를 위해 사용하는 기술이다.
장고가 CSRF 토큰 값을 세션을 통해 발행하고 웹 페이지에서는 폼 전송시에
해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성된 데이터가 전달되는지를 검증하는 기술이다.
csrf_token 사용을 위해서는 CsrfViewMiddleware 미들웨어가 필요한데
이 미들웨어는 settings.py의 MIDDLEWARE 항목에 디폴트로 추가되어 있으므로 별도의 설정은 필요 없다.
[파일명: projects\mysite\config\settings.py]
(... 생략 ...)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
(... 생략 ...)
** csrf_token 기능을 사용하고 싶지 않다면 이 부분을 주석처리 필요
- URL 매핑

** 페이지 새로고침 시 answer_create 별칭을 찾을 수 없다는 오류 발생
질문 상세 템플릿에 {% url 'pybo:answer_create' question.id %}처럼 pybo:answer_create 별칭을 사용했기 때문
[파일명: projects\mysite\pybo\urls.py] 매핑 등록 필요
from django.urls import path
from . import views
app_name = 'pybo' #앱의 네임스페이스 부여
urlpatterns = [
path('',views.index, name='index'), #name속성 부여
path('<int:question_id>/', views.detail, name='detail'), #name 속성 부여
path('answer/create/<int:question_id>/', views.answer_create, name='answer_create'),
]
** answer_create 별칭에 해당하는 URL 매핑 규칙을 등록
** http://locahost:8000/pybo/answer/create/2/ 와 같은 페이지를 요청하면
URL 매핑 규칙에 의해 views.answer_create 함수가 호출
- 뷰 함수
[파일명: projects\mysite\pybo\views.py]
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Question
def index(request):
question_list = Question.objects.order_by('-create_date')
context = {'question_list': question_list}
return render(request, 'pybo/question_list.html', context)
#pybo/question_list.html의 html을 템플릿(Template)이라 한다.
#템플릿은 HTML 파일과 비슷하지만, 파이썬 데이터를 읽어 사용할 수 있는 HTML
def detail(request, question_id):
#question_id 값을 가지고 상세 내용을 모델에서 가져와라
question = get_object_or_404(Question, pk=question_id)
context = {'question': question}
return render(request, 'pybo/question_detail.html', context)
def answer_create(request, question_id):
question = get_object_or_404(Question, pk=question_id)
#create row 생성(내용은 POST 방식으로 넘어온 content, 현재시간)
question.answer_set.create(content=request.POST.get('content'), create_date = timezone.now())
return redirect('pybo:detail', question_id=question.id) # 자신의 페이지에 다시 던져라
** answer_create 함수의 매개변수 question_id는 URL 매핑에 의해 그 값이 전달된다.
http://locahost:8000/pybo/answer/create/2/ 라는 페이지를 요청하면 매개변수 question_id에는 2라는 값이 전달
request.POST.get('content')로 텍스트창에 입력한 내용을 읽을 수 있다.
request.POST.get('content')는 POST로 전송된 폼(form) 데이터 항목 중 content 값을 의미
question.answer_set.create 를 사용하였으며,question.answer_set은 질문의 답변을 의미한다.
Question과 Answer 모델은 서로 ForeignKey 로 연결되어 있기때문 사용 가능
- 답변 조회
[파일명: projects\mysite\templates\pybo\question_detail.html]
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
<!-- 답변 내용 추가 -->
<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
<ul>
{% for answer in question.answer_set.all %}
<li>{{answer.content}}</li>
{% endfor %}
</ul>
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token %} <!-- 보안 관련 항목, form으로 전송된 데이터가 실제 웹 페이지의 작성 데인터인지 가늠 -->
<!-- form태그 밑에 무조건 작성해야 한다. 장고에서 post 방식일 때 {% csrf_token %}이 없으면 에러 발생 -->
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변 등록">
</form>
** question.answer_set.count는 답변의 총 개수를 의미
** question.answer_set는 질문과 연결된 답변들