1. View 다루기
이전 튜토리얼에서는 model을 다루어 보았으니 이번에는 View에 대해서 공부해봅시다.
들어가기전에 MVC와 MTV에 대해서 복습해볼까요?
MVC 는 Model, View, Controller 의 약자이고 MTV는 Model, Template, View 의 약자라고 했습니다.
둘이 이름만 다르지 사실은 같은내용이고 장고에서 MVC를 MTV라고 부른다고 하였습니다.
Model <-> Model
View <-> Controller
Controller <-> View
이렇게 대응됩니다. 고로 장고에서 View는 유저가 보는 웹페이지와 서버의 중간다리라고 생각하시면 됩니다.
이제 polls 어플리케이션에 대한 구체적인 계획을 한번 짜봅시다.
- index 페이지 – Question에 관한 정보를 나타내주는 페이지 입니다.
- detail 페이지 – question text를 상세하게 나타내주는 페이지 입니다. 투표할수 있는 형태로 보여집니다.
- result 페이지 – Question에 관한 결과를 나타내주는 페이지입니다.
- Vote action – 투표하는 기능을 구현할 것입니다.
자그럼 아래 처럼 polls/view.py에 detail, results,vote view를 추가해 줍시다.
polls/views.py
from django.shortcuts import render
from django.http 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)
View를 추가해주셨다면 url에 연결해 줍니다.
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의 root주소는 http://127.0.0.1:8000//polls/ 였죠?
아래코드를 분석하면
path('<int:question_id>/', views.detail, name='detail'),
http://127.0.0.1:8000//polls/퀘스쳔id 를 입력하면 views.py에서 detail view에 연결된다는 뜻입니다.
한번 http://127.0.0.1:8000//polls/34 로 들어가 봅시다.
질문을 34개까지 추가하지 않았는데 34라고 뜨는군요... 여기서 주목할 점은 <int:question_id> 입니다.
url에 <int:question_id>자리에 숫자를 입력하면 int형으로 question_id라는 변수를 만든뒤에 detail view에 넘겨줍니다.
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
그럼 detail view에서 HttpResponse로 "You're looking at question 34." 라는 response를 넘겨주는 것이죠!
파이썬 코드로 생각하면 아래와같이 됩니다.
detail(request=<HttpRequest object>, question_id=34)
이해가 안되신다면 다시한번 차근차근 읽어주세요. 중요한 내용입니다.
127.0.0.1:8000/polls/34/results/
위 링크도 한번씩 들어가 봅시다.
2. 실제로 동작하는 View 만들기
위에 작성한 view는 빈껍데기에 불과합니다. 이번에는 view가 실제로 어떤 기능을 하도록 만들어 봅시다.
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 모델에서 pub_date를 최신순으로 정렬하여 latest_question_list로 받아옵니다.
join 함수를 통하여 각 질문들을 output이라는 문자열로 합쳐주고요. httpresponse로 django에게 넘겨줍니다.
자 그럼 adim 페이지로 가서 question 데이터를 조금 추가해줍시다.
what's up이 제일 먼저 등록되어 있고 question 1~5까지 등록했습니다.
위 코드 기준으로 가장 최신의 데이터 5개만 출력하니 what's up을 제외한 question5부터 question1 까지 나오겠지요?
3. Template 이용하기
자 위의 예제에서 view가 실제로 어떤 동작을 하도록 작성해 보았습니다.
모델과 뷰를 배웠으니 이제 MTV 모델의 템플릿을 배워보겠습니다.
다시 복습해보죠.
모델 : 서버의 데이터베이스
뷰 : 모델과 템플릿의 중간다리 역할
템플릿 : 유저에게 브라우저로 보여지는 웹페이지
이전예제에서 우리는 models.py를 작성하여 데이터베이스를 설계하였고
view를 이용해 데이터베이스 정보를 가져와 웹페이지에 전달까지 해 보았습니다.
템플릿은 간단히 말하면 HTML 파일입니다. 다들 한번씩 학교다닐때 컴퓨터 수업에서 HTML을 해보신적이 있을겁니다.
장고의 Template의 특징은 HTML 코드 일부를 파이썬 코드로 작성할 수 있는 기능을 제공합니다.
먼저 Template파일의 위치에대해서 배워봅시다.
어플리케이션폴더이름/templates/어플리케이션폴더이름/템플릿파일
자 위의 예제에서 polls 어플리케이션의 index 뷰에 관한 템플릿을 만들면
polls/templates/polls/index.html 이 됩니다.
어 그런데 왜 polls를 두번 반복하죠? 그냥 polls/templates/index.html 하면 되지 않나요?
이유는 다음과 같습니다.
장고에서는 템플릿을 찾을때 templates 폴더를 싹다 뒤진뒤 이름만 맞으면 템플릿파일을 가져오게 됩니다.
예를들어 app2에서 abc라는 템플릿을 가져오겠다고 합시다.
app1/templates/abc.html
app2/templates/abc.html
헌데 위와같이 똑같이 app1에서 abc라는 템플릿이 있을경우 장고에서는 이름만 맞으면 되니 app1의 abc를 가져오는 경우가 생깁니다.
이를 방지하기위해 templates 폴더 믿에 polls 폴더를 한번 더 만들어준뒤 템플릿을 넣으라고 권장하고 있습니다.
이를 template namespacing이라고 합니다.
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
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))
자 위의코드는 템플릿을 실제로 작성하고 view와 연동하는 코드입니다.
아까 장고에서 템플릿은 파이썬으로 html코드를 작성하도록 해준다 했죠?
{% %} 이렇게 묶여있는게 파이썬 코드입니다.
코드를 분석해봅시다.
- view에서 index.html을 로드합니다.
- view에서 model에서 Question 데이터를 추출한뒤에 context 라는 딕셔너리에 담습니다.
- template을 rendering 할때 context에서 데이터를 실어담에 템플릿에 정보를 보냅니다.
- template은 context의 담긴 내용을 기반으로 html코드를 파이썬으로 작성합니다
위 코드에서 latest_question_list로 모델에서 데이터를 얻어왔습니다.
그걸 context에 담습니다. 여기서 context는 이삿짐 센터라고 생각하시면 됩니다! 필요한 물품을 여기다 다 담는것이죠!
그리고 latest_question_list 데이터가 유효하면 아래 코드를 돌립니다.
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
라는 코드를 for문으로 여러번 작성하라는 뜻이지요
runserver을 해보면 아래와같이 나옵니다! <li> 코드가 다섯개가 딱 생성되었군요!
브라우저에서 우클릭을 눌러 페이지 원본보기 를 클릭합시다.
<ul>
<li><a href="/polls/6/">question5</a></li>
<li><a href="/polls/5/">question4</a></li>
<li><a href="/polls/4/">question3</a></li>
<li><a href="/polls/3/">question2</a></li>
<li><a href="/polls/2/">question1</a></li>
</ul>
위 파이썬 코드로 html 코드가 작성된걸 확인하실 수 있습니다.
4. render() 함수
위의 views.py 코드에서 loader 하고 httpresponse 하는 작업은 render라는 wrapping 함수로 간략하게 표현될 수 있습니다.
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를 애용합시다.
(wrapping 함수란 다른 함수 여러개 섞어 놓은 작업을 함수로 한번 더 묶어서 한번에 call할수 있도록 하는 함수입니다.)
5. 404 에러 일으키기
이번에는 detail view의 템플릿을 작성해 봅시다.
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 }}
위의 detail views 에서 404 에러를 일으키는 코드는 render와 비슷하게 아래와 같이 shorcut 코드로 작성 될 수 있습니다.
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})
runserver를 한뒤 퀘스쳔을 클릭해보면 detail 내용이 나옵니다.
여기서 잠깐 template 문법에 대해서 말씀드리겠습니다.
{{ 로 시작하고 }} 닫히는 문법은 variable이라고 합니다.
{% 로 시작하고 %} 로 닫히는 문법은 tag라고 합니다.
variable은 말그대로 context에서 넘어오는 변수를 접근하는 syntax이고
tag는 tag내에 파이썬 코드를 실행 시킬 수 있는 syntax입니다.
고로 단순히 변수를 받아오고 싶으면 {{ }} 이걸 쓰면되고
파이썬 코드를 실행시키고 싶으시면 {% %} 하시면 되겠죠?
그럼 이제 아래와 같이 detail view에 choice를 넣어주는 코드를 작성해봅시다
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>
위 코드가 어떻게 돌아가는지 한번 직접 분석해보시기 바랍니다.
6. URL 하드코드 제거하기
다시 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 %}
여기서
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
이부분에서 /polls/ 부분이 하드코드 된것을 볼 수 있습니다.
간단히 말해서 저 href 링크는 detail 뷰로 가는 링크입니다. 이를 아래 처럼 바꿔 줍시다.
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% url %} 태그를 이용하면 위와같이 하드코드가 아닌 유동적인 코드로 바꿔주실 수 있습니다.
사용법은 다음과 같습니다.
{% url (원하는뷰의 url 이름) (url에 인풋으로 들어갈 변수) %]
위 코드에서는 원하는 뷰의 이름은 detail 인데 이 detail의 url 이름은 urls.py에 가보시면 우리가 설정했던걸 아실 수 있습니다!
polls/urls.py
그럼 변수는 여기서 <int:question_id> 에 들어갈 변수겠지요? 여기서 question.id가 저 변수의 인풋으로 들어가게 됩니다!
그림으로 나타내면 이렇게 되겠네요.
7. URL namespacing
자 그런데 url name이 겹치는 경우는 어떻게 할가요?
app1에 detail 이라는 url을 가지고 있고
app2에 detail 이라는 url이 똑같이 있다면?
이를 구분해주기 위해 Django에서는 url namespacing 이라는 기능을 제공합니다.
사용방법은 urls.py 에 app_name 변수를 정의해주는 것입니다.
그럼 detail 템플릿 코드를 아래처럼 바꿔주면 됩니다.
<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>
으로
자. 여러분은이제 MTV 모델에 Model Template View 사용법을 모두 배우셨습니다!
오늘은 푹쉬시길 바랍니다
'Django > 튜토리얼' 카테고리의 다른 글
[Django/장고] 파이썬으로 웹페이지 만들기 튜토리얼 - 6부 (13) | 2021.05.29 |
---|---|
[Django/장고] 파이썬으로 웹페이지 만들기 튜토리얼 - 4부 (5) | 2021.05.22 |
Django/장고] 파이썬으로 웹페이지 만들기 튜토리얼 - 3부 (8) | 2021.05.22 |
[Django/장고] 파이썬으로 웹페이지 만들기 튜토리얼 - 2부 (7) | 2021.05.22 |
[Django/장고] 파이썬으로 웹페이지 만들기 튜토리얼 - 1부 (20) | 2021.05.22 |
댓글