이전에 브라우저에서 요청하면 django에서 어떻게 동작하여 응답하는지 간단한 개념을 알아보았다.
브라우저 -> urls.py -> views.py -> 브라우저 이런 식의 흐름이었다.
이번에는 이 흐름을 조금... 아주 조금 깊이 들어가 보자.
1. 테스트 뷰 만들기
- 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)
- question_id를 받아와서 화면에 보여주라는 내용이다.
- views.py에 내용을 추가했으면 그다음은 urls.py에 해당 함수를 연결하여야 한다.
- 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"),
]
- 주석을 보면 알 수 있듯이 URL 패턴에 따라 연결되는 뷰가 달라진다.
- 예를 들어 하나만 해보겠다. 먼저 서버를 실행시켜 주고, 브라우저에 "127.0.0.1:8000/polls/100/results"를 입력해 본다.
- URL 패턴을 찾아 views.py의 results함수에 연결해 주고 question_id로 받은 100을 출력해 주는 것을 알 수 있다.
2. "뷰"야~ 너 일 좀 하자!!
- polls/views.py에 index() 함수를 아래 내용으로 수정하자. (DB에서 설문 조사가 있다면 5개를 가져와 보여준다.)
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)
- 왼쪽 화면은 관리자 페이지에서 본 Questions의 내용이고 왼쪽은 view에서 보여주는 화면이다.
- 여기서 잠깐!!! views.py에 페이지 내용을 하드 코딩하였다면 코드 자체도 너무 길어질 테고, 관리하기 힘들어질 것이다.
이런 문제를 해결하기 위해 template 시스템이라는 것을 사용한다.
- template 시스템이란 templates 디렉터리에 html 파일을 넣어두고 views.py에서 불러다 쓰는 개념이다.
기본적으로 앱의 하위 디렉터리로 만들어 사용하면 되는데.... 만약 앱이 여러 개라면 보기 싫어진다.
testProj
polls
templates
aaa.html
app_01
templates
bbb.html
app_02
template
ccc.html
- 각 앱의 하위 디렉토리로 templates를 만들어 사용하여도 무방하고.... templates 디렉터리라 빼서 사용할 수도 있다.
testProj
templates
polls
aaa.html
app_01
bbb.html
app_02
ccc.html
- 어떤 것을 사용할지는 사용자 마음이다.
- 두 번째 방법을 사용하려면 설정이 필요한데, setting.py를 수정해 보자.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
- 이제 templates 디렉터리를 만들어 사용하면 된다. ( 본인은 두 번째 방법을 사용할 것이다. )
- templates폴더를 만들고 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 %}
- index.html에게 일을 시키는 주체는 views.py입니다. views.py에서 index.html에 뭔가를 던저주기 위해서 수정이 필요하겠죠?
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))
- html파일을 로드하기 위해 loader를 사용한다.
- 여기까지 했다면 화면이 어떻게 변했는지 확인해 보자.
- 짜잔!!! 바뀐 화면이 보일 것이다.
3. 404 에러 처리하기
- 내가 의도치 않은 일이 벌어진다면 대비를 해야 한다. ( 소프트웨어에서도 마찬가지다. )
- 설문조사가 5가지만 있는데... 어떤 누군가가 100번을 보여달라고 요청하면 어떻게 될까?
이럴 경우는 너무도 당연하게 "너 잘못된 번호를 호출했어!!"라고 에러 페이지를 보여주어야 할 것이다.
- 404 에러는 사용자가 존재하지 않는 경로를 찾을 때 발생한다. ( 여기서는 100번이 없는데, 100번을 보여달라는 것이다.)
- 여기서는 views.py의 detail() 함수에 적용해 보자.
from django.http import Http404
from django.shortcuts import render
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})
- try, except는 정상 적인 루틴에서는 try를 거치고, 예외가 발생했다면 except를 거친다는 말이다.
- detail.html파일이 보인다. 없으니 새로 만들어 주어야 한다. 내용은 아래와 같이 한다.
{{ question }}
- 그럼 detail 페이지를 요청해 보자.
1) 정상 적인 페이지부터 보자.
2) 예외 처리한 페이지를 보자.( 100번을 보여달라고 했을 때이다. )
- 우리가 의도한 404 페이지가 나온다.
3) 예외 처리를 안 했는데, 잘못된 페이지를 요청한 페이지는 어떻게 나올까?
- 알 수 없는 메시지들이 나오면서, 내가 의도하지 않은 화면이 나와 버린다.
- 예외 처리를 하는 이유는 이것 때문이다. ( 잘못된 접근일 때, 내가 의도한 페이지(오류 안내 페이지 등)로 이동할 수 있기 때문이다.)
- 여기서 잠깐!!!
매번 try, except를 사용하기 번거롭다.
번거로운 건 친절한 django씨가 용납하지 않는다는 거!! get_object_or_404()를 사용해 보자.
from django.shortcuts import get_object_or_404, render
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
- try, except를 사용했던 것과 같은 결과가 나온다.
4. 템플릿 시스템을 어떻게 사용할까?
- detail()에서 detail.html로 전달한 question은 어떻게 사용할까?
- html 태그만을 사용해서는 전달받은 데이터를 표현할 수 없다. 변수도 사용해야 되고, 제어문도 사용해야 하는데 html에는 그런 게 없다.
- detail.html을 수정해 보자.
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
- 위 코드를 보면 "{% ~~ %}", "{{ ~~ }}"와 같은 형식의 라인이 보일 것이다. 이는 템플릿 테그라고 한다.
- 템플릿 태그는 여러 종류가 있으며 3가지만 알아보자.
1) "{% ~~ %}" : if, for 루프 같은 Flow Control 문장에서부터 웹 컨트롤처럼 내부 처리 결과를 직접 덤프 하는 등등 여러 용도로 쓰일 수 있다
2) {{ ~~ }} : 변수로서 그 변수의 값이 해당 위치에 치환된다. (객체도 넣을 수 있다.)
3) {# ~~ #} : 코멘트를 넣는 부분이다. 쉽게 이야기해서 주석 처리라 생각하면 된다.
- 코멘트를 여러 줄에 적용하고 싶다면... {% comment %} ~~~ {% endcomment %}를 사용하면 된다.
- 좀 더 많은 템플릿 태그에 대해 알고 싶다면 ( django templates 문서를 참고하기 바란다. )
{# 한개 라인 코멘트 #}
{% comment %}
...(중략)...
불필요한 블럭
...(중략)...
{% endcomment %}
5. 템플릿에서 url 쉽게 관리하기.
- 아래 html 코드를 먼저 확인하자.
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
- 여기서 만약 "/polls/"라는 경로가 바뀐다면??? 인내심이 강인한 나로서는 10개까지는 큰맘 먹고 수정할 자신이 있다.
그렇다면 100개라면?? 아니면 얼마나 많을지 감이 안 온다며?? 대략 난감해진다.
- 이런 일을 미연에 방지하기 위한 것이다. 그럼 어떻게 해야 할까?
- 뭐.... 어려운 일은 아니다. 먼저 polls/urls.py를 보자. ( 저~~ 위에 1. 번에 있지만 올리기 귀찮다.)
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"),
]
- path뒤에 보면 name="~~"라고 있다. 이것을 이용하는 것이다.
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
- 현재는 "polls" 앱 하나만 존재하기 때문에 위와 같이 사용해도 무방하지만 만약 여러 개의 앱이 존재한다면??
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
<li><a href="{% url 'blog:detail' blog.id %}">{{ blog.blog }}</a></li>
<li><a href="{% url 'news:detail' news.id %}">{{ news.news_text }}</a></li>
- 위와 같이 name앞에 앱 이름을 적어주면 된다.
- 크게 바뀌는 부분은 없지만 이렇게 해줌으로 url관리가 쉬워진다.
휴~~ 길다.
씨기도 힘들고, 읽기도 힘들다.
앞으론 짧게 짧게 쓰련다.
오늘도 고생했도.... 앞으로도 파이팅 하자~~
'int main() > django' 카테고리의 다른 글
[ django ] Error during template rendering 에러 (0) | 2023.08.29 |
---|---|
[ django ] 설문 조사 만들기 4 ( 입력 폼 만들기 ) (0) | 2023.08.18 |
[ django ] 설문 조사 만들기 2 (데이터베이스 설치) (0) | 2023.08.10 |
[ django ] 설문 조사 만들기 1 (0) | 2023.08.09 |
[ django ] 시작하기 2. ( pycharm 인터프리터 설정하기) (0) | 2023.08.09 |