2021. 4. 11. 18:48ㆍDev/Django
#View 만들기
View는 Django에서 Model 등을 관리하고 API를 만들고 사용하는 곳이다. NodeJS의 src/api 라고 생각할 수 있을 것 같다. 이곳에서 찾는 모델 또는 모듈을 불러오고, 해당 데이터를 처리한 후 return해주면 응답을 할 수 있다.
응답은 주로 HttpResponse를 통해 HTML로 반환하고, 요청은 HttpRequest를 통해 한다. 요청은 view의 클래스 또는 함수의 첫 번째 인자인 request를 통해 받을 수 있고, 이 request 정보를 바탕으로 Django는 데이터를 처리한 후 response를 해 줄 수 있다.
polls/views.py
#각각의 view가 호출되면, 웹페이지에 HttpResponse의 인자가 출력된다.
#즉, 라우팅을 통해 연결된 view의 내용이 return HttpResponse를 통해 출력된다.
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)
실제로 프로젝트를 진행하면서는 Generic View(추후에 개념 등장)를 더 많이 사용할테지만, Django의 라우팅 방식과 호출되는 함수를 이해하기 위해 HttpResponse를 통해 출력해 보고, 동작 원리를 파악하고 있다.
이후 작성한 view를 라우팅 하기 위해, polls/urls.py에서 path를 수정한다.
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'),
#예를 들어, localhost:포트/polls/3/vote/로 접속하면, 방금 만들었던 views.py의 vote의 HttpResponse가 출력된다.
path('<int:question_id>/vote/', views.vote, name='vote'),
]
여기까지가 View의 기본적인 생성 방법 및 라우팅이다.
#View에 기능 추가하기
그럼 실제로 view가 비즈니스 로직을 처리하도록 해 보자.
http://localhost:8000/polls/ 에 접속했을 때, 가장 최신의 질문 리스트를 발행일에 대한 내림차순으로 5개만 출력해보도록 한다.
polls/views.py에서 index를 다음과 같이 수정한다.
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)
다시 http://localhost:8000/polls/ 에 접속한다면 정상적으로 5개가 내림차순으로 출력되는 것을 볼 수 있는데, 질문 5개의 타이틀이 전부 오른쪽으로 붙어서 알아보기 힘들게 출력됨을 알 수 있다.
물론 프론트 페이지를 따로 만들어서 구현하면 보기 좋게 나올 수 있게 할 수 있지만, Django는 기본적으로 template을 지원하여 마치 프론트 페이지처럼 script를 통해 페이지에 표시할 수 있다.
template을 생성하기 위해 polls에 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 %}
이 템플릿은 latest_question_list가 존재한다면, 리스트 내의 질문들의 question_text를 리스트로 나타내주고, 해당 질문들의 question_text를 클릭 시 href를 통해 detail한 정보를 표시해주는 페이지로 이동하게 해준다.
다시 polls/views.py로 돌아가서 index를 수정한다
from django.http import HttpResponse
#template을 사용하기 위한 모듈 load를import
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
#template을 선언 후, 방금 만든 polls/index.html을 불러온다.
template = loader.get_template('polls/index.html')
#이후 index.html의 latest_question_list 값에 latest_question_list값을 넣고
context = {
'latest_question_list': latest_question_list,
}
#render하여 응답한다.
return HttpResponse(template.render(context, request))
위처럼 만들 수도 있지만, render()를 사용하면 보다 쉽게 만들 수도 있다.
#render를 사용하기 위핸 render import
from django.shortcuts import render
from .models import Question
#위와 동일하지만, template을 따로 선언하고 load하지 않아도 된다.
#render는 3개의 parameter를 갖는데(3번째는 옵션이라 넣지 않아도 됨),
#첫번째는 request,
#두번쨰는 template의 이름,
#세번째는 context 사전형 객체
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)
#물론 context를 굳이 선언하지 않고 아래와 같이 써도 무방하다.
#return render(request, 'polls/index.html', {'latest_question_list': latest_question_list })
#View에 Error 처리하기
error 발생 시, error 처리를 해보자.
예를 들어, detail한 view를 보고싶은데 해당하는 question_id를 가진 질문이 없을 때 404에러를 일으키도록 하자.
#404에러를 발생시키는 모듈 import
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})
더 간단하게 작성하고 싶다면, Django에서 제공하는 get_object_or_404()함수를 쓰면 된다.
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
#get_object_or_404()함수는 함수 이름에서도 알 수 있듯이, Question model에서 pk값이 question_id인 데이터를 가져오고, 없으면 404 에러를 리턴한다.
#첫 번째 인자 : model
#두 번째 인자 : 키워드, 즉 찾고자 하는 옵션
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': 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>
question의 내용을 제목으로 표시하고, 모든 choice들을 리스트의 형태로 표시한다.
#View에 연결된 URL 하드코딩 제거
실제로 프로젝트의 규모가 커진다면 여러 view가 있을 수 있고, 그 중 이름이 같은 view들이 있을 수 있다. 그런데 내가 템플릿의 URL에 하드코딩을 했고, 유지 보수를 생각한다면 그 템플릿들을 수정하고 변경했을 때 잘못된 view들이 호출될 수 있어 고생 좀 할 것이다.
이를 방지하기 위해, polls/urls.py에서 app_name이라는 값을 polls로 설정했다.
polls/templates/polls/index.html을 다음과 같이 변경하자
#기존의 내용을
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
#아래와 같이 변경한다
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
위 코드는 urlpatterns의 name = "detail"인 view에 question.id값을 넣어 url로 이동하는 코드인데 , 만약 동일한 이름을 가진 view가 다른 곳에 있다면 까다로워질 것이다. 따라서 urls.py에 app_name을 넣어 그 중 polls라는 app_name을 가진 urlpatterns의 name = "detail"인 url로 이동하게 할 수 있다. 이렇게 작성한다면 유지보수 및 개발 환경에서 편해질 것이다.
다음에는 Generic View를 이용 및 그 밖의 기능에 대해 공부해보자.
출처 : docs.djangoproject.com/ko/3.1/intro/tutorial03/
첫 번째 장고 앱 작성하기, part 3 | Django 문서 | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
'Dev > Django' 카테고리의 다른 글
Django REST Framework(DRF)로 회원가입/로그인/로그아웃 하기 (0) | 2021.05.17 |
---|---|
Django User DB 커스텀하기 (0) | 2021.05.15 |
Django 시작하기 #1 - App, DBMS 설정 (0) | 2021.04.05 |
Django란? (0) | 2021.03.30 |