21.12.27 Django 튜토리얼 Part3 뷰(페이지) 추가하기

2021. 12. 27. 19:02작업/Django

poll 어플리케이션은 다음과 같은 네 개의 view가 필요하다

질문 색인 페이지 - 최근의 질문들을 표시합니다.

질문 세부 페이지 - 질문 내용 , 투표할 수 있는 서식 표시

질문 결과 페이지 - 특정 질문에 대한 결과 표시

투표 기능 - 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능

 

뷰 추가하기

1. polls/views.py에 요청을 처리하는 함수들 만들기

2. polls/urls.py에 path( route , view , kwargs , name) 호출을 추가하여 새로운 뷰를 polls.urls 모듈로 연결한다.

작동 원리 : 브라우저 URL에 /polls/질문숫자/를 입력하면 detail()함수를 호출하여 URL에 입력한 ID를 출력한다.

사용자가 웹 사이트의 페이지를 예를들어 /polls/34/를 요청하면, 장고는 ex_1222.urls 파이썬 모듈을 불러오게 된다.

ROOT_URLCONF설정에 의해 그 모듈을 바라보도록 지정되어 있기 떄문이다. ex_1222.urls에서 urlpatterns라는 변수를 찾고 순서대로 패턴을 따라간다.

먼저 polls/를 찾고 나면 일치하는 polls/는 버리고 그 뒤에 있는 34/를 polls.urls의 URLconf로 전달하여 남은 처리를 진행한다.

거기에 <int:question_id>/와 일치하면 결과적으로 detail() 뷰 함수가 호출된다.

(다른 경우는 detail, results, vote 등 다른 뷰함수들도 이런 식으로 호출된다.)

 

장고에게 필요한 뷰로 부터 받는 행동은 이 두 가지이다.

- 요청된 페이지의 내용이 담긴 HttpResponse 객체를 반환

- Http404같은 예외를 발생하게 한다.

 

또는 뷰가 데이터베이스의 레코드를 읽을 수도 있고, PDF생성, XML 출력, ZIP파일 만들기 등.. 다 할 수 있다.

 

그럼 이제 index()뷰 하나를 호출했을 때 시스템에 저장된 최소 5개의 투표 질문이 콤마로 분리되어 발행일에 따라 출력되도록 해보자. views.py의 간단한 형태였던 index() 함수를 이렇게 수정한다.

아까 만든 두 개의 질문이 발행일에 따라 , 로 구분되어 출력됐다.

(Num2 Question 과 lol I edited the question in 1227)

그러나 views.py에서 기능만 구현하고 디자인은 따로 할 수 있도록 장고의 html 템플릿을 이용해 기능과 디자인을 분리시켜보자

polls디렉토리 안에 templates라는 디렉토리를 만들면 장고는 그 안에서 템플릿을 찾는다.

프로젝트의 TEMPLATES 설정은 Django가 어떻게 템플릿을 불러오고 렌더링 할 것인지 기술합니다. 기본 설정 파일은 APP_DIRS 옵션이 True로 설정된 DjangoTemplates 백엔드를 구성합니다. 관례에 따라, DjangoTemplates은 각 INSTALLED_APPS 디렉토리의 《templates》 하위 디렉토리를 탐색합니다.

 

Settings | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

polls안에 templates안에 또 polls안에 index.html을 만든다

형식은 플라스크때 봤던 못생긴 jinja형식이다.. 왜 진자를 쓰지..ㅠ

 

아무튼 이 템플릿을 이용해 가장 기본 index 뷰(polls/) 만 쳤을떄 나오는 페이지를 업데이트해보자.

template기능을 사용하기 위해 from django.template에서 loader를 import하고, template.render()라는 함수도 사용하는 것 같다. 

이 코드는  polls/index.html 템플릿을 불러온 후, context를 전달합니다. context는 템플릿에서 쓰이는 변수명과 Python 객체를 연결하는 사전형 값입니다.

return HttpResponse(template.render(context,request))와 같은 기능을 하는 지름길은 render()함수를 사용하는 것이다.

render( request, 템플릿이름.html, context(사전형객체) ) => 인수로 지정된 context로 표현된 템플릿의 HttpResponse객체가 반환된다.

 

404 에러 일으키기

요청된 질문의 ID가 없을 경우 Http404예외를 발생시킨다.

또는 또 shortcuts에 있는 함수 get_object_or_404를 사용할 수도 있다.

get_object_or_404( 모델, 키워드인수 ) 를 get함수로 넘긴다.

get( args, kwargs ) => 주어진 파라미터로 매칭된 오브젝트를 리턴한다. 보통 다음과 같이 필드를 찾을 때? 쓰이는 것 같다. filter()함수와 비슷한 기능인듯?

Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))

질문이 없을 때 404
질문이 있을 때

그럼 이제 detail.html을 수정해서 question이 주어졌을 때 템플릿을 조금 더 꾸며보자

템플릿 시스템은 변숫의 속성에 접근하기 위해 점탐색 문법을 사용한다. 

{{ question.question_text }} 를 보면, 장고는 먼저 question객체에 대해 사전형으로 탐색하고 만약 탐색에 실패하면 속성값으로 탐색을 한다. 속성탐색도 실패하면 리스트의 인덱스 탐색을 시도한다.

질문 있을때 detail.html수정 후

하드코딩된 URL제거하기. a태그에서 저런식으로 url을 적어놓으면 수많은 템플릿을 가진 프로젝트들의 URL을 바꾸는 게 어렵기 때문에 { % url % } 을 이용해서 url설정에 정의된 특정한 URL경로들의 의존성을 제거할 수 있다.

만약 상세 뷰의 URL을 polls/내가원하는것/1/로 더 바꾸고 싶다면 템플릿html파일에서 바꾸는 게 아니라

polls/urls.py에서 바꿔야 한다

...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...

URL의 이름공간(polls뿐 아니라 여러 앱들이 있을 때 이름을 각자 정해주는 것)

이 프로젝트는 polls라는앱 하나만 하지만, 실제 프로젝트는 앱이 몇 개씩 존재한다. 장고는 이 앱들의 URL을 그럼 어떻게 구별해낼까?

장고가 { % url % }템플릿태그를 사용할 때 어떤 앱의 뷰에서 URL을 생성할 지 알수 있을까?

 

=> URLconf에 이름공간(namespace)를 추가하면 된다. polls/urls.py에 app_name을 추가하여 앱의 이름공간을 설정할 수 있다.

polls:detail 로 index.html에서 a태그타고 링크가는 것을 더 구체화해준다.