-
Part 4 폼과 기본 뷰Django 2022. 7. 2. 13:41
간단한 폼 쓰기
polls/detail.html템플릿에 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>기존에 확인했던 What's new?라는 질문을 확인할 수 있는 question_text가 있고
에러 메시지를 전달받게 되면 에러메시지를 출력하는 if문이 보입니다.
label은 이름(choice 목록들)을 보여주고
input은 사용자가 입력할 수 있는것을 보여줍니다.
question에 choice 선택지들을 모두 가지고 와서 반복문(for)을 돌면서 보여지게 됩니다.
(forloop.counter 는 for 태그가 반복을 한 횟수를 나타냅니다.)radio 타입의 choice 목록 버튼들이 나오며
버튼 중 하나를 선택하여 폼을 제출하면 POST 데이터인 choice=#을 보냅니다.
(여기서 #은 선택한 항목의 ID입니다.)POST 양식을 만들고 있기 때문에(데이터를 수정하는 효과가 있을 수 있음),
교차 사이트 요청 위조 때문에 {% csrf_oken %}코드를 넣습니다.(해킹 방지)사용자가 submit 타입의 input버튼(사이트 화면의 vote)을 누르게 되면
해당 url('polls:vote')로 데이터가 전달되게 되고
해당 url에 걸려있는 view(vote( ))에서 데이터를 처리합니다.polls/views.py에 vote( )부분을 다음과 같이 추가해 주세요.
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,)))request.POST 는 키로 전송된 자료에 접근할 수 있도록 해주는 사전과 같은 객체입니다.
이 경우, request.POST['choice'] 는 선택된 설문의 ID를 문자열로 반환합니다.question에 대한 choice들을 가져오게 되는데
이때 (get) 조건이 선택지 중에서 pk값이 템플릿에서 넘겨받은 값을 조회하게 되는겁니다.
만약 POST 자료에 choice 가 없으면,(except 부분)
request.POST['choice'] 는 KeyError 가 일어납니다.위의 코드는 KeyError 를 체크하고,
choice가 주어지지 않은 경우에는 에러 메시지와 함께 설문조사 폼을 다시보여줍니다.데이터가 있는경우에는,(else 부분)
선택지에서 투표를 1올려주고 저장하게 되며
results url('polls:results')로 돌려보내(Redirect)줍니다.
reverse() 함수는 뷰 함수에서 URL을 하드코딩하지 않도록 도와줍니다.polls/views.py에 results( )를 다음과 같이 수정해 주세요.
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})앞 내용에 이어서 (vote( )의 else 부분)
results url('polls:results')에서 results view를 호출하게 되고
question을 조회를 한 다음 results 템플릿('polls/results.html')이 결과 페이지로 보여집니다.
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에 대한 선택지 값들이 반복문을 돌면서 리스트로 반환됩니다.(선택지 이름, 선택지 투표수)
pluralize는 votes가 단수인 경우에는 단수처리를 복수인 경우에는 복수처리를 해주겠다는
장고에서 제공하는 템플릿 기능중 하나입니다.이제, 웹 브라우저에서 /polls/1/ 페이지로 가서, 투표를 해보세요.
투표를 할 때마다 값이 반영된 결과 페이지를 볼 수 있을 것입니다.
만약 설문지를 선택하지 않고 폼을 전송했다면,
오류 메시지를 보게 될 것입니다.제너릭 뷰 사용하기: 적은 코드가 더 좋습니다.
클래스 기반 뷰는 제너릭 뷰라고도 합니다.
제너릭 뷰는 일반적인 패턴을 추상화하여 앱을 작성하기 위해 Python 코드를 작성하지 않아도됩니다.polls/urls.py URLconf를 열어 다음과 같이 변경해 주세요.
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'),
]제너릭 뷰는 함수 기반 뷰와 달리
장고에서 미리 작성된 as_view( ) 함수를 이용하여 view를 호출하게 됩니다.
<question_id> 에서 <pk> 로 변경해주면 됩니다.polls/views.py에 index, detail, results뷰를 다음과 같이 수정해 주세요.
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.함수기반 뷰를 작성했던 소스코드 양이 줄어든 것을 확인할 수 있습니다.
사용할 템플릿 이름, 해당 템플릿에서 사용할 데이터 모델을 적어주면 됩니다.
context에 넘겨주는 이름이 모델 이름과 다르다면
context_object_name을 정해주고
필요한 데이터를 get_queryset( ) 함수를 통해서 작성해주면 됩니다.출처 : django 웹 프로그래밍 강좌 (#4 form, generic view)(django form 사용, 데이터 받아오는 법, generic view 사용)
'Django' 카테고리의 다른 글
Part 6 정적 파일 (0) 2022.07.03 Part 5 테스팅 (0) 2022.07.02 Part 3 뷰와 템플릿 (0) 2022.07.01 Part 2-2 관리자 페이지 (0) 2022.06.29 part 2-1 모델 (0) 2022.06.29