Django - 튜토리얼 part3 (View 개선 / 템플릿 추가)

Joey Lee·2020년 4월 30일
0

Django

목록 보기
3/23

View 추가하기

장고에서 View는 특정기능과 템플릿을 제공하는 웹페이지이자 모듈이다. polls 앱에서는 아래와 같은 4개의 뷰를 가지고 있다.

  • "index" page : 질문 표시
  • "detail" : 질문 및 서식 표시
  • "results" : 특정 질문에 대한 결과 표시
  • 투표기능 : 질문에 대해 투표할 수 있는 기능
from django.shortcuts import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)

이렇게 생성된 새로운 View들은 polls.urls 모듈로 연결시켜 준다.

from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

urlpatterns 리스트 중 2번째 항목은 views.py 안에 있는 detail()을 통하여 url에 입력한 ID 값을 출력하게 되고, 해당 url을 통해 투표 서식을 보게 된다. 결과적으로 detail()엔 아래와 같은 값이 전달된다.

detail(request=<HttpRequest object>, question_id=34)

View가 실제로 뭔가를 하도록 만들기

앞에서 작성한 View는 polls에 필요한 기능들을 정의하긴 했지만, 실제로 투표와 관련해서 별도의 기능을 구현하지는 않았다. 따라서 앞의 4개 View가 실제로 무엇가를 하도록 하려면 다음과 같이 코드를 보완하여야 한다.

우선, 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 %}

이제 템플릿을 이용해 polls/views.py에 index.html를 직접 로드해서 HttpResponse 객체로 리턴해 줍니다.

polls/views

from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

하지만 이 내용을 보다 축약하기 위한 단축기능인 render()를 이용하여, 아래와 같이 코드를 다시 작성합니다.

from django.shortcuts import render

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

질문내역(ID)가 없는 경우에 404 에러를 예외처리하기 위해 detail() 함수 코드를 아래와 같이 정리합니다.

from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})

하지만 앞써 index() 함수에서와 유사하게 예외처리 또한 get_object_or_404 메소드를 통해 보다 간결하게 코드를 작성할 수 있습니다.

from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})

템플릿 시스템 사용하기

템플릿에 detail.html 코드를 다음과 같이 입력합니다.

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

템플릿 문법을 이용하여 하드코딩된 url를 제거하여 코드를 아래와 같이 다시 고칠 수 있습니다.

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <!-- <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> -->
        <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

URL의 이름공간 정하기

장고 프로젝트에는 앱이 몇 개라도 추가될 수 있습니다. 앱들마다 어떻게 url를 구별할 수 있을까요? 정답은 URLconf에 이름공간(namespace)를 추가하는 것입니다. polls/urls.py 파일에 app_name을 추가하여 어플리케이션의 이름공간을 설정할 수 있습니다.

polls/urls.py

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    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'),
]

이제 기존 polls/index.html 파일의 내용을 아래와 같이 이름공간으로 나눠진 상세 뷰를 가르키도록 수정한다.

polls/templates/polls/index.html

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
profile
안녕하세요!

0개의 댓글