Polls 앱에 클래스형 뷰 적용


이번 챕터에서는 지난번에 함수형 뷰로 만들었던

polls앱을 클래스형 뷰로 바꿔보고자 합니다.

(클래스형 뷰로 작성하는 습관을 들여야 합니다.)


먼저 books앱 템플릿과 일관성을 위해

base_polls.html 생성하도록 하겠습니다.

mysite/templates/base_polls.html

{% extends 'base1.html' %}

{% block title %}Polls Application Site{% endblock %}

{% block sidebar %}
{{ block.super }}
<ul>
    <li>
        <a href="/polls/">Polls_Home</a>
    </li>
</ul>
{% endblock %}


그 다음, index, vote, results 템플릿을 수정하겠습니다.


mysite/polls/tempaltes/polls/index.html

{% extends 'base_polls.html' %}

{% block content %}

<h2>Polls Question List</h2>

{% if object_list %} <!--views.py의 index함수에서 context를 통해 넘겨준 questions-->
    <ul>
        {% for question in questions %} <!--python3 for 문법과 동일-->
            <li>
                <a href="{% url 'polls:vote' question.id %}">{{question.question_text}}</a> <!--데이터 객체내에 필드명 접근 방법-->
            </li>
        {% endfor %}
    </ul>
{% else %}
    <p>No question data</p>
{% endif %}

{% endblock %}

polls/templates/index.html에선

‘mysite/templates/base1.html’을 extends했고,

기존의 코드를 block content로 둘러싸고,

href부분을 하드코딩에서 url명령어를 써서 만드는 걸로 바꿨습니다.


vote와 results도 바꿔보겠습니다.

mysite/polls/templates/polls/vote.html

{% extends 'base_polls.html' %}

{% block content %}

<h1>{{question.question_text}}</h1>

{% if error_message %}
    <p><strong>{{error_message}}</strong></p>
{% endif %}

<form action="{% url 'polls:vote_process' question.id %}" method="post">
    {% csrf_token %}
    {% 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 %}
    <input type="submit" value="Vote" />
</form>

{% endblock %}


mysite/polls/templates/polls/results.html

{% extends 'base_polls.html' %}

{% block content %}

<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:index' %}">Vote again?</a>

{% endblock %}

둘다 기존 코드에 extends를 추가하고,

block content로 감싼걸 알 수 있습니다.


다음으로 mysite/polls/views.py를 고쳐보겠습니다.

이번에 여기서 고칠 함수는 index, vote, results입니다.

(템플릿 고친 그대로죠)

기존의 index, vote, results함수는 주석처리하거나 지우고,

다음의 IndexView, VoteView, ResultsView를 추가해줍니다.

from django.views.generic import ListView, DetailView


class IndexView(ListView):
    template_name = 'polls/index.html'
    context_object_name = 'questions'

    def get_queryset(self):
        """
        return the last five published questions.
        """
        return Question.objects.order_by('-pub_date')[:5]


class VoteView(DetailView):
    model = Question
    template_name = 'polls/vote.html'


class ResultsView(DetailView):
    model = Question
    template_name = 'polls/results.html'

IndexView에 보면 처음보는 context_object_name이 보입니다.

원래 이렇게 설정을 안하면 템플릿에서 ‘object_list’로 접근해야합니다.

하지만 우린 index.html을 고칠 때, 거기서 쓰는 변수를

고치지 않아서 questions 그대로 써야하죠?

이럴때는 context_object_name을 이용해 접근 변수를 설정할 수 있습니다.


또한 여기서는 get_queryset메소드가 새로 보입니다.

전에 books앱을 만들 땐, model = Question 이런 식으로만 써서

query를 object_list로 템플릿에 넘겨줬었습니다.

하지만 다른(혹은 커스텀한) query를 넘겨주고 싶으면

get_queryset을 이용해 해당값을 리턴해주면 됩니다.


나머지는 django tutorial ch3-3에서 다 스터디했던 내용입니다.


이제 함수형에서 클래스형 뷰로 변경해준만큼 urls.py도 변경해줄 차례 입니다.

mysite/polls/urls.py

from django.conf.urls import url, include
from polls import views

urlpatterns = [
    # url(r'^$', views.index, name='index'),
    # url(r'^(?P<question_id>\d+)/$', views.vote, name='vote'),
    # url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.VoteView.as_view(), name='vote'),
    url(r'^(?P<pk>\d+)/results/$', views.ResultsView.as_view(), name='results'),
    url(r'^(?P<question_id>\d+)/vote/$', views.vote_process, name='vote_process'),
]

이번 변경사항에 필요한 사항만 적은 것입니다.

아마 처음부터 제 django tutorial을 따라오신 분들이면

예제를 위한 url 코드가 더 있을 것입니다.


URL은 그대로인데, 함수형 뷰로 연결되있던게 클래스형 뷰로 연결되도록 변경되었습니다.


바뀐(더 간단해진) 코드를 다시 보며

로컬서버를 켜고, localhost:8000에 접속 후, polls앱에 접속해봅니다~


localhost:8000 에 접속했을 때, 1.img_localhost

polls앱을 클릭했을 때, 2.img_clicked_polls