[Django] 3. 장고 튜토리얼 part.3

김학재·2021년 12월 21일
0

백엔드

목록 보기
4/8
post-thumbnail

어플리케이션과 어드민이 완성되었으니 이제 투표(polls) 어플리케이션에 공개 인터페이스인 뷰(view)를 추가할 차례!


개요

뷰는 장고 어플리케이션이 특정 기능과 템플릿을 제공하는 웹페이지의 한 종류
예를 들어, 블로그 어플리케이션의 경우

  • Blog 홈페이지
  • 세부 페이지
  • 월별 축적 페이지
    등의 뷰를 가질 수 있다.

여기서는 총 4개의 view를 만들어 본다

  • 질문 색인 페이지 : 최근의 질문들 표시
  • 질문 세부 페이지 : 질문 내용과, 투표할 수 있는 서식 표시
  • 질문 결과 페이지 : 특정 질문에 대한 결과 표시
  • 투표 기능 : 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능 제공

뷰 추가하기

# polls/views.py
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)

path() 호출을 추가해 새로운 뷰를 polls.urls 모듈르 연결

# polls/urls.py
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'),
]

사용자가 웹사이트의 페이지를 요청할 때 예를 들어 /polls/34/를 요청하면, Django는 mysite.urls 파이썬 모듈을 불러온다.
mysite.urls에서 urlpatterns라는 변수를 찾고, 순서대로 패턴을 따라간다. 일치하는 패턴을 찾으면 일치하는 텍스트를 버리고 남은 텍스트를 URLconf로 전달해 남은 처리를 진행한다.


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

뷰는 페이지의 내용이 담긴 HttpRespone 객체를 반환하거나 Http404 같은 예외를 발생하게 해야한다

Django에 필요한 것은 HttpResponse 객체 혹은 예외

# polls/views.py
from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

뷰에서 사용할 수 있는 템플릿을 작성해 파이썬 코드로부터 디자인을 분리하도록 템플릿 시스템을 사용한다

polls 하위에 templates 디렉토리 생성

<!-- polls/templates/polls/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>This is title</title>
  </head>
  <body>
    {% 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 %}
  </body>
</html>

polls/views.py에 index 뷰 업데이트

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]
    # polls/index.html 템플릿을 불러온 후, context를 전달
    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)

404 에러 일으키기

Http404를 사용한다

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})
<!-- polls/templates/polls/detail.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>This is title</title>
  </head>
  <body>
    {{ question }}
  </body>
</html>

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})

템플릿 시스템 사용하기

<!-- polls/templates/polls/detail.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>This is title</title>
  </head>
  <body>
    <h1>{{ question.question_text }}</h1>
    <ul>
    {% for choice in question.choice_set.all %}
        <li>{{ choice.choice_text }}</li>
    {% endfor %}
    </ul>
  </body>
</html>

템플릿에서 하드코딩된 URL 제거하기

AS_IS
<li>
  <a href="/polls/{{ question.id }}/">
    {{ question.question_text }}
  </a>
</li>
TO_BE
<li>
  <a href="{% url 'detail' question.id %}">
    {{ question.question_text }}
  </a>
</li>
# polls/urls.py
# 여기서 name 값이 template의 {% url %} 로 인해 호출된다
path('<int:question_id>/', views.detail, name='detail')

URL의 이름공간 정하기

여러 앱의 URL을 구별하기 위해 URLconf에 이름공간을 추가한다

polls/urls/py에 아래 코드 추가

...

app_name='polls'
urlpatterns = [
   ...
]

그리고 polls/index.html 템플릿을 아래와 같이 변경

<li>
  <a href="{% url 'polls:detail' question.id %}">
    {{ question.question_text }}
  </a>
</li>
profile
YOU ARE BREATHTAKING

0개의 댓글