728x90
반응형
1. 폼 등록하기
기본적으로 우리는 데이터를 주고 받을 때 form이용하여 받고는 한다. 이를 이용해서 장고에서 데이터 전달과정을 보고자 한다.
// pybo\\question_detail.html
<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>
- 우리가 이전에 question을 등록했으므로 이에 대한 답변을 받기 위한 form을 만들어 준다. 그리고 이는 textarea에 적으면 button을 클릭하면 넘어가는 형식을 구현하였다.
- 답변 저장을 위한 URL : form 태그의 action 속성에 {% url 'pybo:answer_create' question.id %}로 지정했다.
- {% csrf_token %} : 보안에 관련된 항목으로 form으로 전송한 데이터가 실제 웹 페이지에서 작성한 데이터인지를 판단하는 가늠자 역할을 한다.
- 어떤 해커가 이상한 방법으로 데이터를 전송할 경우에는 서버에서 발행한 csrf_token 값과 해커가 일방적으로 보낸 csrf_token 값이 일치하지 않기 때문에 블록킹될 것이다.
- CSRF란? CSRF(cross site request forgery)는 웹 사이트 취약점 공격을 방지를 위해 사용하는 기술이다. 장고가 CSRF 토큰 값을 세션을 통해 발행하고 웹 페이지에서는 폼 전송시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성된 데이터가 전달되는지를 검증하는 기술이다.
- POST 요청시 form 태그에 csrf_token이 없으면 장고는 오류를 낸다.
반응형
2. URL 매핑하기
위에서 pybo:answer_create 별칭을 사용했다. 이를 urls에 지정해줘야 오류가 나지 않는다.
// pybo\\urls.py
from django.urlsimport path
from .import views
app_name = 'pybo'
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'),
]
answer_create 별칭에 해당하는 URL 매핑 규칙을 등록했다. answer/create/2/ 와 같은 페이지를 요청하면 URL 매핑 규칙에 의해 views.answer_create 함수가 호출된다.
3. 뷰 함수 작성하기
위에서 urls.py에 작성한 views.answer_create가 없으면 오류가 발생하므로 이와 같은 함수를 작성해주도록 한다.
1) 뷰 함수 작성방법
// pybo\\views.py
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('pybo:detail', question_id=question.id)
- question_id : answer_create 함수의 매개변수 question_id는 URL 매핑에 의해 그 값이 전달된다. question_id에 대한 질문을 가져와야 하므로 이가 필요하다.
- request : 답변 등록시 텍스트창에 입력한 내용은 answer_create 함수의 첫번째 매개변수인 request 객체를 통해 읽을 수 있다. request.POST.get('content')로 텍스트창에 입력한 내용을 읽을 수 있다.
2) 뷰 함수 작성방법
// pybo\\views.py
from .models import Question, Answer
(... 생략 ...)
def answer_create(request, question_id):
"""
pybo 답변등록
"""
question = get_object_or_404(Question, pk=question_id)
answer = Answer(question=question, content=request.POST.get('content'), create_date=timezone.now())
answer.save()
return redirect('pybo:detail', question_id=question.id)
- 질문을 가져오고, 이에 답변을 작성하기 위해서 answer 테이블에 들어갈 데이터를 넣어주고 이를 저장하는 방법도 있다.
- redirect 함수는 페이지 이동을 위한 함수이다. 질문 상세 화면을 다시 보여주기 위해 redirect 함수를 사용한다. 그리고 pybo:detail별칭에 해당하는 URL은 question_id가 필요하므로 question.id를 인수로 전달했다.
4. 답변 조회하기 위한 템플릿 작성하기
3번까지 작성한 것은 답변을 작성하면 저장하는 것까지 했다. 답변을 조회한 것을 템플릿에 보여줄 수 있도록 코드를 작성해야 한다. 아래와 같이 작성해보자.
// pybo\\question_detail.html
<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
<ul>
{% for answer in question.answer_set.all %}
<li>{{ answer.content }}</li>
{% endfor %}
</ul>
</div>
- question.answer_set.count는 답변의 총 갯수를 의미한다.
Form
1) 뷰 함수 추가하기
: 페이지 요청시 전달되는 파라미터들을 쉽게 관리하기 위해 사용하는 클래스이다. 폼은 필수 파라미터의 값이 누락되지 않았는지, 파라미터의 형식은 적절한지 등을 검증할 목적으로 사용한다. 이 외에도 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 모델의 속성
장고의 폼은 일반 폼(forms.Form)과 모델 폼(forms.ModelForm)이 있다.
- 모델 폼 : 모델(Model)과 연결된 폼으로 폼을 저장하면 연결된 모델의 데이터를 저장할 수 있는 폼이다.
- 모델 폼은 이너 클래스인 Meta 클래스가 반드시 필요하다. Meta 클래스에는 사용할 모델과 모델의 속성을 적어야 한다.
즉, Question 모델과 연결된 폼이고 속성으로 Question 모델의 subject와 content를 사용한다고 정의한 것이다.
2) 템플릿 추가하기
// 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 }} : 폼을 <p> HTML 태그를 사용하여 랜더링하는 것을 말한다. 폼의 각 필드를 p 태그 안에서 레이블과 텍스트로 배치한다.
- 폼을 랜더링하는 옵션으로 form, form.as_p, form.as_table, form.as_ul 등이 있는데, 이 옵션은 각 필드를 어떤 HTML 태그로 Wrapping 할 것인가를 지정하는 것이다.
- action : form 태그에 action 속성을 지정하지 않으면 현재 페이지의 URL이 디폴트 action으로 설정된다.
3) 기능 뷰 함수 추가하기
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)
- POST 방식
- request.POST : request.POST를 인수로 QuestionForm을 생성할 경우에 request.POST에 담긴 subject, content 값이 QuestionForm의 subject, content 속성에 자동으로 저장되어 객체가 생성된다.
- form.is_valid() : form이 유효한지를 검사한다.
- 만약 form에 저장된 subject, content의 값이 올바르지 않다면 form에는 오류 메시지가 저장되고 form.is_valid()가 실패하여 다시 질문 등록 화면을 렌더링한다.
- question = form.save(commit=False) : form에 저장된 데이터로 Question 데이터를 저장한다. create_date 속성은 없기 때문에 commit=False로 임시 저장한다.
- form.save() : question 객체를 리턴받고 create_date에 값을 설정한 후 실제 데이터를 저장한다.
- create_date 속성은 데이터 저장 시점에 생성해야 하는 값이므로 QuestionForm에 등록하여 사용하지 않는다.
- GET 방식에서는 form = QuestionForm() 처럼 QuestionForm을 인수 없이 생성한다.
👇🏻 참고사이트
728x90
반응형