"polls/views.py"
from django.http import HttpResponse
from django.template import loader
from .models import Question
from django.http import Http404
from django.shortcuts import get_object_or_404, render
def index(request):
latest_question_list = Question.objects.order_by("-pub_data")[:5]
temlplate = loader.get_template("polls/index.html")
context ={
"latest_question_list":latest_question_list,
}
return HttpResponse(temlplate.render(context,request))
def detail(request, question_id):
question = get_object_or_404(Question,pk=question_id)
return render(request, "polls/detail.html", {"question": question})
def results(request, question_id):
respone = "You're looking at the result of question %s"
return HttpResponse(respone % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s" % question_id)
"-pub_data"에서 -은 내림차순을 뜻함
loader.get_templeate("polls/index.html")에서 polls/index.html은 직접 디렉토리를 만들고 그 안에 html문법을 통해 형태를 만들어야 한다.
"polls/urls.py"
from django.urls import path
from .import views
app_name = "polls"
urlpatterns = [
# ex: /polls/
path("", views.index, name="index"),
# ex: /polls/5/
path("<int:question_id>/",views.detail, name="detail"),
path("<int:question_id>/results/",views.results,name= "results"),
path("<int:question_id>/vote/",views.vote, name = "vote"),
]
path()를 호출해 만들어둔 뷰와 연결을 시켜 준다.
polls/urls.py 파일에 app_name을 추가하여 어플리케이션의 이름공간을 설정한다. 이름 공간을 설정하면 같은 이름을 가진 URL의 충돌을 방지할 수 있다.
ex) detail -> polls:detail
이제는 polls디렉토리 안에 templates디렉토리를 생성하고 안에 polls디렉토리를 만들고 그 하위에 index.html을 작성한다.
"polls/templates/polls/index.html"
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
"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>
"polls/view.py" 중 vote부분을 수정한다.
from django.db.models import F
from django.http import HttpResponse, HttpResponseRedirect
from .models import Question, Choice
from django.urls import reverse
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 = F("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,)))
# ex) polls/3/results
| 기능 | 설명 |
|---|---|
| 질문 가져오기 | get_object_or_404(Question, pk=question_id)를 사용하여 주어진 question_id에 해당하는 질문 객체를 가져옵니다. 질문이 존재하지 않으면 404 오류를 반환합니다. |
| 선택된 선택지 가져오기 | request.POST["choice"]를 통해 사용자가 선택한 라디오 버튼의 값을 가져옵니다. 이 값을 사용하여 해당 선택지를 찾습니다. |
| 예외 처리 | - KeyError: 사용자가 선택을 하지 않았을 때 발생합니다. - Choice.DoesNotExist: 존재하지 않는 선택지 ID를 사용했을 때 발생합니다. |
| 오류 메시지 표시 | 예외가 발생하면 질문 폼을 다시 렌더링하고, "You didn't select a choice."라는 오류 메시지를 표시합니다. |
| 투표 수 증가 | 선택된 선택지의 투표 수를 1 증가시킵니다. F("votes")를 사용하여 데이터베이스에서 직접 값을 증가시키고, 이를 저장합니다. |
| 리다이렉트 | 투표 완료 후 결과 페이지로 리다이렉트합니다. reverse("polls:results", args=(question.id,))를 사용하여 URL을 생성합니다. |
result도 코드를 수정한다.
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/results.html", {"question": question})
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>
제너릭 뷰는 주로 CRUD(Create, Read, Update, Delete) 작업을 효율적으로 수행하기 위해 사용된다.
polls/urls.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"),
]
polls/views.py 를 다음과 같이 수정한다.
from django.db.models import F
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.
...