Web/Django

Django - 데이터 저장

괘창 2024. 5. 18. 19:16

● 데이터 저장

- 답변 등록 폼

[파일명: 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는 질문과 연결된 답변들