[Django] tutorial #4-form
form
을 이용하여 클라이언트인 사용자로부터 서버쪽으로 데이터를 불러오는 방법을 알아보려고 한다.
저번 part3에서 만든 뷰는 함수기반이었다.
이번에는 class
기반으로 뷰를 만들어보려고 한다.
class기반 뷰로 구현하면 소스코드가 줄어든다는 장점이 있다.
간단한 form
만들기
polls/detail.html
파일을 수정하여, 템플릿에 form
요소를 추가해준다.
- polls/templates/polls/detail.html
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
코드를 살펴보자면,
데이터를 전송을 위한 요청방식을 post
방식으로 하기 위해 post
를 명시해주었다.
사용자가 서버로 데이터를 보내주기 위하여 form
태그와 input
태그를 사용하였다.
사용자가 submit type
의 input tag
을 누르면 해당 url인 polls:vote
로 데이터가 전달되고, 해당 url에 연결되어 있는 뷰인 views.vote
가 데이터를 처리를 하게 된다.
이때 뷰로 전달되는 데이터는 value
값이다.
여기서 해당코드가 사용되는 이유는 다음과 같다
{% csrf_token %}
: 사이트 위조요청으로, 해킹방지를 위해 사용한다.
우리는 이미 polls
앱을 위해 아래에 나와있는 코드를 포함하는 URLconf
를 만들어 두었다.
- polls/urls.py
path('<int:question_id>/vote/', views.vote, name='vote'),
또한 가상으로 만들어 두었던 vote()
함수를
실제로 구현 하기 위해 다음과 같이 수정해준다.
polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
# ...
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
다음 코드를 해석해보자면,
def vote(request, question_id)
:vote
뷰를 호출할때question_id
를 넘겨 받음question = get_object_or_404(Question, pk=question_id)
:question_id
를 넘겨 받으면 question데이터를 조회except (KeyError, Choice.DoesNotExist):
: 조회했을 때 데이터가 없으면 예외가 발생return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", })
: 예외가 발생했을 때 다시detail.html
(상세페이지)로respose
를 해주며,context
데이터로question
과error_message
를 보내줌else: selected_choice.votes += 1 selected_choice.save()
: 조회했을 때 데이터가 있으면 choice를 1 올려주고 저장return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
:reverse
함수를 통해results
뷰를 호출.
이때reverse
는 뷰 함수에서url
을 하드코딩하지 않도록 도와줌
수정 후 서버를 확인해보면 만들어준 form
을 확인 할 수 있다.
results
뷰 만들기
사용자가 설문조사에 설문을 하고나면, vote
뷰는 설문조사 결과 페이지result
를 호출한다.
따라서 result
뷰를 작성해보려고 한다.
- polls/view.py
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
results
뷰는 question
을 조회한 다음, results.html
을 결과페이지로 보여준다.
이때 question
데이터가 템플릿으로 전달된다.
따라서 결과페이지를 만들기 위한 템플릿을 작성해준다.
- polls/templates/polls/results.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
뷰로부터 question
데이터를 받아와,
question_text
가 제목이 되고
question에 대한 선택지(choice)
값들이 반복문을 돌며 리스트로 들어간다.
여기서 처음보는 키워드에 대해 알아보자면,
vote{{ choice.votes|pluralize }}
:pluralize
는votes
가 단수인 경우는 단수처리를, 복수인 경우는 복수처리를 하는 장고에서 제공하는 템플릿 기능이다.
위와 같이 처음보는 키워드가 있다면 외우는 것이 아니라 키워드에 대해 구글링 해서 찾아보면 된다
이제 서버에서 설문에 대한 투표를 하고나면, 결과페이지(results)
를 확인할 수 있다.
generic
뷰 사용하기
class
기반의 뷰를 generic
뷰라고도 한다.
generic
뷰는 일반적인 패턴들에 대해 장고에서 만들어놓았기 때문에 함수형 기반 뷰에 비해 코드량이 적다.
generic
뷰를 사용하기 위해 url
과 views
코드를 수정해준다.
- polls/url.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
generic
뷰는 장고에서 미리 작성 된 as_view
함수를 호출하여 뷰를 호출하게 된다.
이때 detail
이나 results
url
에서도 int:question_id
라는 파라미터 이름을 지우고 pk
만 명시해주면 된다.
여기서 pk
란 db내의 하나의 열, 즉 하나의 데이터를 구분할 수 있는 값이다. pk
값은 중복되지 않는다
- polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
... # same as above, no changes needed.
이렇게 generic
뷰에서는
사용할 템플릿 이름, 해당 템플릿에서 사용할 데이터 모델을 명시해주기만 하면 된다.
이때 context
에 넘겨주는 데이터의 이름이 모델이름과 다르다면 context_object_name
을 다시 정해주고,
필요한 데이터를 get_queryset
함수를 이용해서 다시 작성해주면 된다.
generic
뷰는 정형화된 작업들이 이미 만들어져 있어 기능들을 익혀 간편하게 사용할 수 있는 것이다.
하지만 장고에 익숙해질때 까지는 함수 기반 뷰를 작성하는 것을 추천한다!
🔎 참고
디장고 공식문서
디장고 공식문서 강의자료
Author And Source
이 문제에 관하여([Django] tutorial #4-form), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jollyn/Django-tutorial-4-form저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)