티스토리 뷰

study/Django

Django tutorial 따라하기 3

xoxowo 2022. 6. 29. 23:22

튜토리얼3 에서는 앞서 만든 튜표 어플리케이션(polls)의 공개 인터페이스인 뷰(view)를 다음과같이 4개를 만들어 보자.

  • 질문 “색인” 페이지 – 최근의 질문들을 표시합니다. (index)
  • 질문 “세부” 페이지 – 질문 내용과, 투표할 수 있는 서식을 표시합니다. (detail)
  • 질문 “결과” 페이지 – 특정 질문에 대한 결과를 표시합니다 (resulrts)
  • 투표 기능 – 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능을 제공합니다. (vote)

 

뷰(view) 추가하기

튜토리얼에 나와있는 대로 polls/views.py 에 4개의 뷰(view)를 보이기 위한 코드를 추가한다. (편하게 말하자면 클라이언트가 보는 웹페이지 화면)

# 최근 질문들을 표시하는 '색인' 페이지
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))
    
# 질문 내용과, 투표할 수 있는 서식이 있는 '세부' 페이지
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):
    response = "You're looking at the results of quesion %s"
    return HttpResponse(response % question_id)
    
# 특정 질문에 대해 선택을 할 수 있는 투표 기능 페이지
def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)

추가하였다면 path() 호출을 추가하여 새로운 뷰를 polls.urls 모듈과 연결한다. 

from django.urls import path

from . import views

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

 

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

클라이언트가 어떤 요청을 하면 요청된 페이지의 내용이 담긴 HttpResponse 객체를 반환하거나 Http404와 같은 예외를 발생하게 해야한다고한다.

튜토리얼에서는 장고의 라이브러리를 사용하는 여러가지 방법을 알려주고있다.

 

템플릿 시스템 사용하기

polls/views.py는 뷰 페이지 디자인이 하드코딩 (고정?)되어있어 페이지의 디자인을 바꾸고싶다면 장고의 템플릿(templates)시스템을 사용하면된다.

 

튜토리얼에서 polls 디렉토리 안에 templates 디렉토리를 만들고 그 안에 또 polls 디렉토리를 만들어 그 내부에 index.html 파일을 만들라고 되어있는데 그냥 templates 디렉토리에 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 %}

그리고 polls/views.py 파일에 index 부분에 추가를 해주었다. 이 코드는 polls/index.html 템플릿을 불러온 후, context를 전달한다.

(이 때 context는 템플릿에서 쓰이는 변수명과 Python 객체를 연결하는 사전형 값이다.)

 

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를 불러와서 return 한다
    template = loader.get_template('polls/index.html')
    # context를 통해서 template에 데이터를 전달해준다
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

 

어떤 코드가 어디에 전해지는지 간단하게 표기해봤는데.. 아직 완벽하게 이해하지 못했다.ㅠㅜ 

 

 

지름길로 render() 함수를 사용하면 쉽게 표현할 수 있다. 

 

404 에러 일으키키

404 예외를 발생 시키기위해 try eccept 구문을 이용하여 만들 수도 있다.

만약 클라이언트가 우리가 생성하지 않은 Question의 페이지를 보려고한다면 404에러가 나타나는 것을 확인 할 수 있을 것이다.

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

지름길로 get_object_or_404() 함수를 사용하면 쉽게 표현할 수 있다. 

 

템플릿 시스템 사용하기

위 에서 index 일때 보여지는 파일을 html 파일을 만든 것처럼 detail(Question 목록)가 보이는 화면을 만들기 위해 detail.html 파일도

polls /templates/polls/ 에 추가하고 아래 코드를 입력하였다.

<h1>{{ question.question_text }}</h1>
<ul>
 // question을 fk(외래키)로 가지고있는 choice의 모든 값을 가져오는 코드 
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

question.question_text 변수를 <h1> 태그로 감싸줬기 때문에 구현 화면에 아래와 같이 폰트 사이즈가 커진 것을 확인 할 수 있고 이 question을 fk(외래키)로 가지고 있는 choice의 모든 값도 <li> 태그로 나열되어 있는 것을 확인할 수 있다.  

 

'템플릿 시스템은 변수의 속성에 접근하기 위해 점-탐색(dot-lookup) 문법을 사용합니다. 예제의 {{ question.question_text }} 구문을 보면, Django는 먼저 question 객체에 대해 사전형으로 탐색합니다. 탐색에 실패하게 되면 속성값으로 탐색합니다. (이 예에서는 속성값에서 탐색이 완료됩니다만) 만약 속성 탐색에도 실패한다면 리스트의 인덱스 탐색을 시도하게 됩니다.' - 장고 튜토리얼 전문 발췌

 

 

템플릿 시스템 사용하기

polls 어플의 detail() view를 보면 context 변수 question이 주어졌을 때 detail.html이 어떻게 동작하는지 살펴보자.

 

 

 

 

 

템플릿 시스템은 변수의 속성에 접근하기 위해 점-탐색(dot-lookup) 문법을 사용한다.

<h1> 태그 내부의 {{ question.question_text }}를 살펴보면 장고는 이 question 객체에 대해 사전형으로 탐색하고 탐색에 실패하면 속성값으로 다시 탐색한다. 만약 속성 탐색에도 실패하면 리스트의 인덱스 탐색을 시도한다.

 

<h1>{{ question.question_text }}</h1>
<ul>
// for 반복 구문에서 메소드 호출이 일어나며 question을 fk로 가지고있는 choice의 모든 객체가 for문으로 모두 출력된다
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

 

 

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

polls/index.html 템플릿에 링크를 적으면, 이 링크는 다음과 같이 부분적으로 하드코딩되는데, 이 하드코딩의 문제는 수 많은 템플릿을 가진 프로젝트들의 URL을 바꾸는게 어려운 일이 된다는 것이다.

 

polls.urls 모듈의 path() 함수로 인수의 이름을 정의한 것을 바탕으로 {% url %} template 태그를 이용하여 URL 경로의 의존성을 제거할 수 있다.

# 기존 .html 정의했던 url 링크
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

# path()함수를 정의하여 {% url %} 태그 이용
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

 

 polls.urls 모듈에 서술된 URL 의 정의를 탐색하는 식으로 동작하며, polls/urls.py에서  ‘detail’ 이라는 이름의 URL 이 어떻게 정의되어 있는지 확인할 수 있다.

# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),

만약 url을 polls/specifics/12로 바꾸고싶다면 polls/urls.py에서 바꿔야한다.

# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),

 

URL의 이름 공간 정하기

이 장고 튜토리얼에서는 하나의 앱만 만들어보았는데, 추후 여러 앱이 추가될 수도 있다. 이때 URLconf에 이름공간(namespace)를 추가하면 어플리케이션의 이름공간을 설정할 수 있다. 

 

polls/ursl.py 파일에서 이름공간(namespace)을 추가한 후 .html 파일의 url 부분을 수정해야한다.

from django.urls import path
from . import views

# 이름공간 (namespace) 추가
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'),
]

// 기존 url 'detail' 에서
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
// url 'polls:detail' 변경
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

 

 


내용 전문 및 출처 -djangoproject

'study > Django' 카테고리의 다른 글

Django - MtoM Field 없이 구현  (0) 2022.07.06
westarbucks 만들기 - models.py  (0) 2022.07.05
Django tutorial 따라하기 4  (0) 2022.06.30
Django tutorial 따라하기 2  (0) 2022.06.29
Django tutorial 따라하기 1  (0) 2022.06.28
댓글