Django Tutorial : View
4개의 뷰를 만듭니다.
각각은 다음과 같습니다.
색인(Index) - 최근의 질문 표시
세부(Detail) - 질문 내용, 투표할 수 있는 서식 제공
결과(Result) - 특정 질문에 대한 결과 제공
투표(vote) - 특정 질문에 대해 선택할 수 있는 기능 제공
urls.py의 path()호출로 view들을 polls.url로 연결합니다.
이때, view에 페이지의 디자인이 하드코딩 돼 있다면, 페이지를 바꾸기 위해 python코드를 편집해야만 합니다. 따라서, 코드와 디자인을 분리하기 위하여 view에서 사용할 수 있는 템플릿을 작성해줍니다.
polls디렉토리 내에 templates라는 디렉토리를 만들고, 그 안에 polls 디렉토리를 또 만들고, 그 안에 index.html을 만듭니다. 즉, 다음과 같은 구조입니다.
polls/templates/polls/index.html
이는 DjangoTemplates가 각 설치된 app의 디렉토리의 templates하위 디렉토리를 탐색하기 때문입니다. ... 무슨 말일까요 이게?
mysite내에 app1 , app2 두개의 앱이 있다고 가정하면 장고가 인식하는 template폴더는 다음과 같습니다.
- app1/templates
- app2/templates
- mysite/templates
1번 폴더에 없으면 2번폴더로, 2번에도 없으면 3번으로 이동하며 장고는 템플릿을 찾습니다.
근데 만약 찾으려는 파일이 app1/templates 안에도 있고, app2/templates안에도 있다면 원하는 파일을 찾아오지 못 할 수 있다는 문제가 생깁니다. 따라서 templates폴더 내부에 하위 폴더로 app이름의 폴더를 또 하나 만들어서 관리해주는 것이 편리한 것입니다.
app1/templates/app1/test.html
이런 식으로 디렉토리를 만들어서 관리하게 되면, html파일 앞에 app 경로가 추가되기 때문에, 중복되어 로딩될 수 없습니다.
이러한 경로로 작성된 템플릿을 이용하여, view를 업데이트 할 수 있습니다.
polls/templates/polls/index.html의 코드입니다
1 2 3 4 5 6 7 8 9 | {% 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 %} |
템플릿을 이용하여 index view를 업데이트 하면 다음과 같습니다. 이때 render()라는 구문이 사용됩니다. 이는 context(템플릿 변수명과 python 객체를 연결하는 딕셔너리 값) 를 채워넣어 표현한 결과를 HttpResponse 객체와 함께 돌려주는 구문입니다.
1 2 3 4 5 6 7 8 | 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) |
이번에는 detail() view를 업데이트 해줍니다.
get_object_or_404()를 사용하는데, get()을 사용하여 Http404 예외를 발생시키는 단축 기능입니다.
1 2 3 4 5 6 7 | 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}) |
get_object_or_404의 첫 인자는 Django 모델이고, pk를 키워드 인수로 넘깁니다. 만약 객체가 존재하지 않는다면, Http404 예외가 발생합니다.
detail 템플릿을 확인해봅시다.
1 2 3 4 5 6 | <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> |
{{ question.question_text }} 구문에서 django는 question 객체에 대해 dictionary형으로 탐색합니다, 만약 탐색에 실패하게 되면 속성값으로 탐색합니다. 속성 탐색에도 실패한다면, 리스트 인덱스 탐색을 시도합니다.
{% for %} 구문에서 question.choice_set.all()코드로 해석되는 question.choice_set.all은 Choice객체의 반복자를 반환합니다. 이를{% for %} 구문에서 반복자로 사용합니다.
앞서 index.html을 보면, 하드코딩(데이터를 코드 내부에 직접 입력함) 된 부분이 있습니다.
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
polls.urls 의 path()함수에서 인수의 이름을 정의했기에,
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
django는 URLconf에 namespace(이름공간)을 추가함으로써 여러가지 앱들의 URL을 구분합니다. polls/urls.py 파일에 app_name을 추가하여 어플리케이션의 이름공간을 설정합니다.
1 2 3 4 5 6 7 8 9 10 11 | from django.urls import path 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'), ] |
app_name = 'polls'를 추가해줍니다
그 이후, 템플릿의 기존 내용에 namespace로 상세 view를 가리키도록 변경해줍니다.
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
여기서 url 'detail'을 url 'polls:detail'로 바꿔주면 됩니다.