polls app에 다음 4가지 view를 추가하기 위해,
질문 《index》 페이지 – 최근의 질문들을 표시
질문 《detail》 페이지 – 질문 내용과, 투표할 수 있는 서식을 표시
질문 《results》 페이지 – 특정 질문에 대한 결과를 표시
투표 기능 《vote》 – 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능을 제공
일단 아래와 같이 views.py
에 내용을 추가하여 보았다.
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)
그리고 새로운 view를 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/》 이 주소에 접속하면
You're looking at question 34.
detail()
함수를 호출하여 URL 에 입력한 ID 를 출력한다.
《/polls/34/results/》 와 《/polls/34/vote/》 도 마찬가지로,
You're looking at the results of question 34.
You're voting on question 34.
라는 화면이 각각 출력된다.
예를 들어 《/polls/34/》를 요청했다고 하면, 출력까지 다음과 같은 과정을 거친다.
Django는 <mysite.urls>
파이썬 모듈을 불러오게 된다.
ROOT_URLCONF 설정에 의해 해당 모듈을 바라보도록 지정되어 있기 때문이다.
<mysite.urls>
에서 urlpatterns
라는 변수를 찾고, 순서대로 패턴을 따라간다.
polls/
를 찾은 후엔, 일치하는 텍스트("polls/"
)를 버리고, 남은 텍스트인 "34/"
를 〈polls.urls〉
URLconf로 전달하여 남은 처리를 진행한다.
거기에 '<int:question_id>/'
와 일치하여, 결과적으로 detail()
뷰 함수가 호출된다.
views.py를 조금 수정하여, 실제로 polls app의 역할을 하게 만들어보았다.
polls/views.py
from django.http import HttpResponse
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)
# Leave the rest of the views (detail, results, vote) unchanged
작성된 Question들 중에 작성 날짜를 내림차순으로 정렬하여 5개를 불러오는
즉, 최근 작성된 5개를 순서대로 출력하는 것이다.
하지만 이렇게 되면, 웹 페이지의 디자인을 바꾸기 위해서는 views.py
의 index를 직접 수정해야하는 번거러움이 있다.
이를 해결하기 위해 Template를 사용할 수 있는데,
일단 아래와 같은 디렉토리에 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 %}
그리고 views.py
를 다음과 같이 수정해주면,
polls/views.py
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))
작성한 Template를 불러와서 답해주는 구조이다.
latest_question_list
를 만들어서 그 데이터를 index.html
Template에 전달을 하면, 이 데이터를 사용하여 그 형태로 값을 전달해 주는 것이다.
실제로 확인해보면,
전에 저장해놓았던 id=1
이고, 'What's up?'이라는 Question에 링크를 걸어서
<li><a href="/polls/1/">What's up?</a></li>
와 같이 출력되는 것을 확인 할 수 있다.
위와 같이 Template에 context를 채워넣어 표현한 결과를 HttpResponse 객체와 함께 돌려주는 구문은 자주 쓰는 용법이다.
따라서 Django는 이런 표현을 쉽게 표현할 수 있도록 단축 기능(shortcuts)을 제공하고 있다.
index() 뷰를 단축 기능으로 작성하면 다음과 같다.
polls/views.py
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)
render( ) 함수는 request 객체를 첫번째 인수로 받고, Template 이름을 두번째 인수로 받으며, context 사전형 객체를 세번째 선택적(optional) 인수로 받는다.
인수로 지정된 context로 표현된 Template의 HttpResponse 객체가 반환된다.
Question의 detail에 질문과 답변 내용을 보여주게 만들어보자.
일단 detail 페이지의 template을 만들기 위해 아래와 같이 추가한다.
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>
Question의 text가 제목<h1></h1>
으로 나오고
그에 해당하는 Choice의 text들이 <li></li>
로 출력된다.
그리고 views.py 아래와 같이 내용을 수정해주면,
polls/views.py
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})
datail.html
template에 question
을 지정해주고,
만약 요청된 질문의 ID가 존재하지 않을 경우 Http404
예외를 발생시킨다.
이 Http404
예외를 render()
로 표현해줄 수 있는데,
polls/views.py
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})
이와 같이 작성하여도 정상적으로 Http404
가 실행되는 것을 볼 수 있다.
get_object_or_404()
함수는 Django 모델을 첫번째 인자로 받고,
몇개의 키워드 인수를 모델 관리자의 get()
함수에 넘긴다.
만약 객체가 존재하지 않을 경우, Http404
예외가 발생하게 된다.
index.html template를 보면,
polls/index.html
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
이런식으로 하드코딩이 되어있는 것을 확인 할 수 있다.
url을 Template에 하드코딩 하게 되면 url 변경 시 Template에 있는 코드들도 변경해 주어야 한다.
이는 url 수정에 대한 어려움이 늘어나는 것으로 크게 도움이 되지 않는다.
Django에서는 url 마다 urls.py
에 있는 name
을 명시하여 이를 해결하는데 도움을 준다.
polls/index.html
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
이처럼 url 코드에 name
을 명시해서 Template에 그 네임을 직접 써주면,
하드코딩 된 url이 변경되더라도 고유의 name
을 갖고 있기 때문에
Template 안에있는 url의 변경을 할 필요가 없게 된다.
하지만 지금처럼 app이 polls 하나인 경우가 아니라,
여러 개의 app들에서 동일한 name
의 url을 가지는 경우에는
{% url %} 이 어떤 앱의 뷰에서 URL을 명시하는지 알 수 없다.
이를 해결하기 위해 polls/urls.py
에 app의 이름을 지정하고,
polls/urls.py
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'),
]
기존 Template의 내용을 다음과 같이 수정하면 'polls:detail'
과 같이,
특정한 이름을 가진 app의 name
의 지정이 가능해진다.
polls/templates/polls/index.html
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
참조
(https://docs.djangoproject.com/ko/3.1/intro/tutorial03/)
포스팅 감사합니다~!