django에서의 view는 특정 기능과 알고리즘을 수행하며 template을 제공해 주는 역할을 하는 웹페이지이자 모듈이다. polls 앱 기준으로 다음과 같은 4개의 view를 구성해 볼 수 있다.(실제 MVC 디자인 패턴에서 Controller에 해당한다, 또한 View는 django에서 template이나 FE단의 페이지가 될 수 있다)
from django.shortcuts import HttpResponse
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)
URL 패턴 또한 URLConf를 통해 간결하게 만들 수 있으며 해당 패턴을 view에 연결 시켜 주기도 한다.(URL dispatcher 참고)
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'),
]
urlpatterns 리스트 안 두번째 path 메소드를 간단히 설명하면 views.py 안에 있는 detail()
을 통하여 URL에 입력한 ID를 출력하게 되어 있고 해당 url을 통하여 투표 서식을 볼 수 있다. 결과적으로 detail()
엔 다음과 같이 값이 전달된다
detail(request=<HttpRequest object>, question_id=34)
view가 어떤 식으로 동작하는지 템플릿의 연결관계와 더불어 튜토리얼에서 설명하고 있다. 이 파트에선 그 과정을 요약해서 한번에 정리한다.
먼저 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 %}
원래는 아래와 같이 template을 직접 load 해서 HttpResponse 객체를 리턴하게끔 되어 있지만 django에선 이걸 축약해서 render 메소드를 통해 구현하게 끔 되어 있다.
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))
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})
이 또한 shortcuts 모듈 안에 있는 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})
요약하면 views.py에서 복잡한 처리 과정이 있는데 shortcuts 모듈 안에 있는 메소드들이 간단히 구현하게 해준다는 것이다.
템플릿 문법 또한 기존에 html/css와는 다른 모습에 이질적이지만 어느정도 잘 활용할 줄 안다면 url경로의 의존성을 줄이거나 반복문이나 조건문의 사용을 통해 긴 코드도 짧게 줄일 수 있는 장점이 있다.
<!-- 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>
템플릿 문법을 이용하여 하드코딩된 url 제거하는 방법 예제
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<!-- <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> -->
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
실제 django 프로젝트는 앱이 몇개라도 추가가 될 수 있다. 그렇다면 그 많은 app들 중에 URL을 어떻게 구분할까 ? 다시 말해 polls라는 앱에 detail이 있을 수도 있고 같은 프로젝트 내에 blog라는 앱에도 detail이라는 view가 있을 수도 있다. 이를 구분하기 위해 URLConf에 namespace를 추가한다.
# 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/index.html의 템플릿의 기존 내용을 아래와 같이 수정한다(어디에서 온 view인지 명시)
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
https://docs.djangoproject.com/ko/3.0/intro/tutorial03/
하지만 요즘 개발 트렌드에서 template을 합쳐 full-stack으로 구현하는 추세가 아니기에 template 부분은 거의 만들지 않고 FE 개발로 그 역할이 넘어가 있는 편이다. 따라서 템플릿은 일단 참고로 알아 두고 정 필요하다 싶으면 찾아가며 쓰는 정도로 정리해두는게 맞을 듯 싶다.