일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 금융IT #코스콤 #금융보안원 #금융경제연구소
- BCG # 불주사 # 코로나 불주사
- 배달의 명수 #배달의 민족
- 오거돈 #부산시장 #오거돈시장 성추행 #오거돈 사퇴
- 5G #5G단점 #5G 4G
- 텔레그램 #가해자처벌 #청원동의 #n번방 #박사방
- 코로나19 #복수 여권 #교통비할인
- Today
- Total
nul-problog
[Django/장고 tutorial 4] View (view 사용, html 연결) 본문
목표 : 장고 view를 살펴보고, 템플릿인 html 파일을 연결한 후 url , view, 템플릿이 어떻게 연결되는지 확인해보기!
view는 장고 웹의 logic을 담당하는데 웹에서 일어나는 데이터 저장, 파일 다운로드와 같은 일들을 처리하기 위해서 코드를 작성한다.
poll 애플리케이션에서 다음과 같은 4개의 view를 만들어 보기
- 질문 “색인” 페이지 – 최근의 질문들을 표시
- 질문 “세부” 페이지 – 질문 내용과, 투표할 수 있는 서식을 표시
- 질문 “결과” 페이지 – 특정 질문에 대한 결과를 표시
- 투표 기능 – 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능 제공
'색인, 세부, 결과, 기능 ' 이 네 가지 기능에 대해서 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)
뷰는 명심해야 할 것이 한 가지 있다!
뷰에서는 request 인자를 받고 HttpResponse라는 함수를 리턴하게 된다. 이때 client로부터 request를 받게 되면 request에는 여러 가지 정보가 담겨있고 이를 다시 Response 해준다는 개념을 명심해야 한다.
response 해주기 전에 뷰에서는 데이터를 추출, 저장하기도 할 것이고 파일을 다운로드하기 위한 로직을 작성하기도 할 것이다.
- 뷰를 호출하기 위해서 urls 코드를 작성해야 한다.
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'),
]
작동원리
1. "http://127.0.0.1:8000/polls/34"와 같이 웹사이트에서 페이지를 요청
2. 장고에서 ROOT_URLCONF 설정이 가리키는 mysite.urls 모듈을 로드한다.
3. mysite.urls 에서 urlpatterns라는 변수를 찾고 그중 polls/를 찾는다.
4. 'polls/'에서 일치 항목을 찾은 후에 'polls/'를 제거하고, 나머지 텍스트 '34/'를 추가 처리하기 위해 'polls.url' URLconf로 보낸다.
5. 남은 '34/' 텍스트는 'polls.url'의 '<int:question_id>/'와 일치하여 다음과 같이 detail() View를 호출한다.
detail(request=<HttpRequest object>, question_id=34)
6. 요청 결과
따라서,
-> cliet 가 polls라고 호출을 하게 되면 views.index라는 뷰를 호출하게 되고 "Hello, world. You're at the polls index"를 화면에 출력한다.
-> polls 다음에 question_id로 5, 그리고 results를 전달해 줬다면 results뷰를 호출하게 되고 "You're looking at the results of question 5"를 화면에 출력한다.
.
- '<int:question_id>/vote/' 이와 같은 형태는 장고에서 지원하는 urls의 패턴이다. 이때 urls의 question_id는 views에 있는 파라미터 중 question_id와 동일해야 한다.
뷰가 실제로 무언가를 하도록 만들기
각 뷰에서는 요청된 페이지의 콘텐츠가 포함된 httpresponse를 반환하거나, Http404 같은 예외를 발생시키는 두 가지 작업 중 하나를 수행한다. 이 작업이 리턴되기 전에 뷰는 데이터베이스 레코드를 읽을 수도 있고, python third-party(파이썬 서드파티)에서 제공되는 템플릿을 사용하는 등 웹에 맞는 작업을 할 수 있다.
현재 코드는 HttpResponse를 통해 "Hello, world. You're at the polls index" 스트링만 출력이 되는데, 이 대신 Question을 직접 가지고 와서 출력하도록 해보겠다. polls/urls.py의 index() view를 아래의 코드처럼 수정한다.
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5] # Question 데이터 중에서 게시날짜를 정렬하여 5개까지만 데이터를 가지고옴
output = ', '.join([q.question_text for q in latest_question_list]) # 5개 데이터를 ',' 로 연결하여 스트링으로 만들어줌
return HttpResponse(output)
위 코드는 페이지의 디자인이 view에 하드 코딩되어 있는 문제가 있다. 개발자가 페이지에 표시되는 방식을 변경하려면 해당 파이썬 코드를 매번 편집해야 한다. 따라서 장고의 템플릿 시스템을 사용하여 view에서 사용할 수 있는 템플릿을 만들어 파이썬과 디자인을 분리해야 한다.
먼저 polls 디렉터리에 templates 디렉터리를 만든다. 장고는 여기에서 템플릿을 찾는다.
이 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 디렉터리를 만들지 않고 templates에 바로 index.html 파일을 만든다면 장고는 다른 앱의 템플릿과 구분할 수 없다.
다음으로 템플릿을 사용하여 polls/views.py에 index view를 수정하자.
from django.template import loader
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))
-> polls/index.html 템플릿을 불러온 후 context를 전달
-> context는 템플릿에서 쓰이는 변수 명과 python 객체를 연결하는 딕셔너리
브라우저에 "/polls/" 페이지를 지정하여 로드하면 앞서 저장한 질문 두 개가 표시된다.
question_id가 잘 전달되었는지 궁금하다면 f12 키를 눌러 확인할 수 있다.
A shortcut: render()
render 함수를 사용하게 되면 코드 양을 줄일 수 있다. 템플릿을 로드하고, 콘텍스트를 채우고, 렌더링 된 템플릿의 결과로 HttpRespone 객체를 반환하는 것은 매우 일반적이며 장고는 이에 대한 shortcut을 제공한다.
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)
-> 뷰에서 이 작업을 한번 수행하면 더 이상 loader와 Httpresponse를 import 하지 않아도 된다.
-> render() 함수는 request 객체를 첫 번째 인수로, 템플릿 이름을 두 번째 인수로, dictionary를 선택적 세 번째 인수로 갖는다.
404 에러 발생시키기
프로그래밍을 할 때 간권중 하나가 얼마나 에러 처리를 잘하냐 이다.
- polls/views.py detail 변경
from django.shortcuts import render
from django.http import HttpResponse, Http404
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})
-> question에 데이터가 없는 경우 (question_id를 통해 question을) 'Question does not exist' 출력
polls/templates/polls/detail.html 파일도 잊지 말고 추가하기
A shortcut : get_object_or_404()
장고는 http404 발생시키는 것에 대한 shortcut을
try : except 처리 없이 shortcut을 사용하여 코드를 작성할 수 있다.
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})
템플릿 시스템 사용하기
polls/detail.html 템플릿을 다음과 같이 수정해보자
<h1>{{ question.question_text }}</h1> <!--템플릿에 question을 넘겨받고 question내의 question_text 를 제목으로 보여줌 -->
<ul>
{% for choice in question.choice_set.all %} <!-- question을 외래키로 사용하는 choice들을 가지고 옴-->
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
브라우저에 "/polls/1/" 페이지를 지정하여 로드하면 다음 화면이 나오는데 현재 "what's up"을 외래 키로 사용하는 choice가 없기 때문에 choice_list 가 출력되지 않는다.
admin에서 choice를 등록해보자.
polls/admin.py 파일을 수정하고 (Choice 추가)
from django.contrib import admin
from .models import Question,Choice
admin.site.register(Question)
admin.site.register(Choice)
admin 페이지에 Choices가 추가됨을 확인한다.
Question을 선택한 후 choice text를 작성하여 저장한다.
브라우저에서 "/polls/1/""/polls/1/"을 다시 실행하면 추가한 choice_list를 확인할 수 있다.
템플릿에서 하드코딩된 URL 제거하기
index.html 템플릿을 보면 url 부분이 하드코딩되어있다.
-> 문제점 : 하드코딩으로 밀접하게 연결된 방식이기에 템플릿이 많은 프로젝트에서는 url을 변경하기 어렵다.
코드를 작성할 땐 항상 "어떻게 해야 수정에 대한 영향범위를 줄일 수 있을까" 고민해야한다.
장고에서는 url 마다 name을 명시할 수 있다. name을 명시해서 템플릿에 그 name을 직접 써주게 되면 하드코딩된 url이 변경되더라도 고유name을 가지고 있기 때문에 템플릿url에 대해서는 소스코드를 변경할 필요가없다.
따라서 아래 코드로 수정한다. (name 'detail' 로 작성)
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
URL 이름 네임스페이스
현재 튜토리얼은 polls 앱 하나만 가지고 있지만, 실제 장고 웹 프로젝트에서는 훨씬 더 많은 앱들을 작성하게된다.
따라서 이러한 앱들의 URL을 구분할 수 있도록 URLconf 에 네임스페이스를 추가해야한다.
만약 polls 앱이 아닌 다른앱에서도 detail을 사용한다면 app_name을 통해 해당앱을 명시해주면된다.
템플릿에도 polls 를 추가해주면 된다.
"{% url 'detail' question.id %}" --> {% url 'polls:detail' question.id %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
'Django' 카테고리의 다른 글
[ERROR] Django http 통신 http: error: argument REQUEST_ITEM: '' is not a valid value Error (0) | 2022.12.07 |
---|---|
[Django/장고] Django - Mysql 연동하기 (2) | 2022.12.04 |
[Django/장고 tutorial 1] 장고 app(app 생성, 서버 구동) (1) | 2022.11.21 |
[Django/장고 tutorial 3] admin 사용 (0) | 2022.11.16 |
[Django/장고 tutorial 2] 데이터베이스(model 생성, API 사용) (0) | 2022.11.16 |