[Django] tutorial #3-view
view
추가하기
뷰를 추가하기 위해 polls/views.py
를 열어 다음 코드를 작성해준다.
- polls/views.py
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)
여기서 명심해야 할 것은
뷰에서는 클라이언트로 부터 request
를 받게 되고, 다시 response
를 반환 해준다는 것이다.
이때 request
에는 많은 정보들이 담겨있다.
response
를 해주기 전에 뷰에서는 데이터를 추출할 수도 있고 저장할 수 도 있으며, 웹에 맞는 다양한 처리를 해줄 수 있다.
추가해준 뷰를 호출하기 위해 polls/urls.py
를 열어 url 코드를 작성해준다.
- 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/
주소로 index
뷰가 호출이 되고,
호출 된 index
뷰가 "Hello, world. You're at the polls index." 라는 respose
를 클라이언트에게 반환해주는 것이다.
다음은 장고에서 지원하는 url 패턴이다.
-<int:question_id>/
-<int:question_id>/results/
-<int:question_id>/vote/
여기서 주의해야할 점은
url 코드에 명시된 question_id
는 뷰에 있는 파라미터 중 question_id
와 일치해야한다는 점이다.
view
가 실제로 뭔가를 하도록 만들기
현재까지는 index
뷰를 호출했을 때
"Hello, world. You're at the polls index."라는 str을 반환했다면,
이젠 시스템에 저장된 최소한 5개의 투표질문이 콤마로 분리되어, 발행일에 따라 출력되도록 해볼 것이다.
- 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
이제 index
뷰가 호출되면 클라이언트로 부터 request
를 받아,
Question
데이터 중 출판일자(pub-date)
를 정렬하여 5개
까지 가져오고, 이를 콤마(,)
로 연결하여 str으로 반환해주게 된다.
templates
분리하기
지금까지는 클라이언트에게 보여지는 페이지가 뷰 내에 있었다. 데이터를 추출하여 바로 클라이언트에게 반환해주는 방식인 것이다.
하지만 이러한 방식은 디자인 수정시 클라이언트에게 보여지는 페이지 수정이 매우 복잡해진다.
디자인을 수정하기 위해 뷰 내부를 수정해야하기 때문이다
따라서 내부로직 담당인 뷰와 디자인 담당인 템플릿을 분리시켜줘야 한다 !
우선 polls
디렉토리에 templates
라는 디렉토리를 만들어준다.
이때 templates
디렉토리 내에 앱 이름(polls)
으로 디렉토리를 또하나 만들어 html
파일을 관리해줘야 한다.
그 이유는 앱이름의 디렉토리를 또하나 만들어 주지 않으면 장고가 다른 앱의 템플릿과 구분하지 못하기 때문이다.
polls/
migrations/
templates/polls
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/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))
코드를 살펴보자면,
teplate
을 load
해서 respose
를 반환해주는 것이다.
이때 context
를 통해서 템플릿의 데이터를 전달해준다.
latest_question_list
데이터를 템플릿에 전달해주면 템플릿에서 해당 데이터를 사용하게 되는 것이다.
템플릿은 뷰로부터 데이터(latest_question_list)
를 받아 리스트를 만들어서 클라이언트에게 보여준다 !
render()
로 코드량 줄이기
render
함수를 사용하게 되면 코드량을 줄일 수 있다.
장고에서는 정형화된 작업의 소스코드를 줄이기 위해 간단한 함수로 표현할 수 있도로 단축 기능(shortcuts)
를 제공한다.
- 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)
404 예외 일으키기
프로그래밍을 할때 에러를 얼마나 잘 처리하는 가는 중요한 부분이다.
detail
뷰에 에러를 발생시켜보려고 한다.
- 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})
- polls/templates/polls/detail.html
{{ question }}
코드를 작성해준 뒤 없는 데이터를 조회하면 에러가 나타나면서 예외 메시지인 "Question does not exist"를 반환해준다
get_object_or_404()
데이터가 존재하지 않을때 get()
을 사용하여 Http404 예외를 발생시키는 것은 자주 사용한다. 장고는 이 기능에 대한 단축 기능(shortcuts)
을 제공한다.
방금 전 작성한 detail
뷰를 단축기능을 사용하면 다음과 같이 수정할 수 있다.
- 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})
템플릿 시스템 사용하기
detail
뷰도 context
변수인 question
이 주어졌을 때, polls/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>
이때 코드 해석을 해보자면, 다음과 같다
<h1>{{ question.question_text }}</h1>
: 템플릿은question
을 넘겨받고question
데이터 내의question_text
를 제목으로 보여준다{% for choice in question.choice_set.all %}
:question
을 외래키(ForeignKey)
로 받는choice
들을 모두 가져온다<li>{{ choice.choice_text }}</li>
: 가져온choice
를 리스트에다
하나씩 넣어준다
코드 수정 후 서버를 확인해보면 question_text
가 제목이 되고,
그 아래 choice
의 모든 목록들이 보이는 것을 확인 할 수 있다.
템플릿에서 하드코딩된 url
제거하기
현재 index.html
파일의 url
부분이 하드코딩 되어있다.
- polls/templates/polls/index.html
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
이렇게 될 경우 url
변경 시, 템플릿에 있는 url
들도 일일히 변경해줘야 된다.
이를 개선하기 위해서
장고에서는 url
마다 name
을 명시해줄 수 있다.
url
코드에 name
을 명시해주고, 템플릿에 그 name
을 직접 써주게 되면
수정이 있어도 url
의 고유네임이 있기 때문에 템플릿 내의 소스코드를 변경해줄 필요가 없게 되는 것이다 !
따라서 하드코딩된 url
을 제거하기 위해 다음과 같이 코드를 수정해준다.
- polls/templates/polls/index.html
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
이때 해당 url
의 고유네임은 polls/ulrs.py
파일에서 확인할 수 있다.
- polls/ulrs.py
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
url
의 이름공간 정하기
지금까지는 polls
라는 앱 하나만 있었지만,
실제 프로젝트를 하면 앱이 여러개가 있을 수 있다.
polls
앱에서 detail
이라는 뷰를 가지고 있고, 예를 들어 또 다른 blog
앱에서도 동일하게detail
이라는 뷰를 가질 수 있다.
이때 방금 위에서 했던 것처럼
템플릿에서의 url
태그를 {% url %}
이렇게 해준다면, 장고는 어떤 앱의 뷰에서 생성된 url
인지 구분할 수 없다.
따라서 장고가 앱마다의 url
을 구분할 수 있도록,
다음과 같이 해당 앱에서 사용하는 url
에 대해서 앱 이름을 명시해줘야 한다.
- 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'),
]
이름을 명시해준뒤 템플릿에도 추가해준다.
- polls/templates/polls/index.html
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
🔎 참고
디장고 공식문서
디장고 공식문서 강의자료
Author And Source
이 문제에 관하여([Django] tutorial #3-view), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jollyn/Django-tutorial-3-view저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)