본문 바로가기

Django/따라하는 장고

8. 템플릿

[질문 목록]

 

http://localhost:8000/pybo/ 페이지에 들어가면 등록한 질문을 볼 수 있도록 구현해 보자.

pybo/views.py 파일의 index 함수를 다음과 같이 수정하자.

 

질문 목록 데이터는 Question.objects.order_by('-create_date') 로 얻을 수 있다. order_by는 조회 결과를 정렬하는 함수이다. order_by('-create_date')는 작성일시 역순으로 정령하라는 의미이다. "  -  " 기호가 붙어 있으면 역방향, 없으면 순방향 정렬을 의미한다. 게시물은 보통 최신순으로 보기 때문에 작성일시의 역순으로 정렬한다.

 

render 함수는 파이썬 데이터를 템플릿에 적용하여 HTML로 반환하는 함수이다. 즉, 위에서 사용한 render 함수는 질문 목록으로 조회한 question_list  데이터를 pybo/question_list.html 파일에 적용하여 HTML을 생성한 후 리턴한다. 여기서 사용된 pybo/question_list.html과 같은 파일을 템플릿이라고 부른다. 템플릿 파일은 HTML 파일과 비슷하지만 파이썬 데이터를 읽어서 사용할 수 있는 HTML 파일이다. 

 

[템플릿 디렉토리]

 

render 함수에서 사용한 pybo/question_list.html 템플릿 파일을 작성해야 한다. 하지만 템플릿 파일을 작성하기 전에 템플릿 파일을 저장할 디렉토리를 먼저 만들어야 한다. 템플릿을 저장 할 디렉토리는 config/settings.py 파일의 TEMPLATES 항목에 설정해야 한다.

DIR는 템플릿 디렉토리를 여러개 등록할 수 있도록 리스트로 되어 있다. 파이보는 BASE_DIR/'templates' 디렉토리 한 개만 등록한다. 여기서 BASE_DIR 은 /Users/h<사용자명>/projects/mysite 이다.

결론적으로 전체 경로는 /Users/<사용자명 >/projects/mysite/templates 이다. 이  디렉토리는 없으므로 다음과 같이 생성하자.

가상 공간 (mysite) 에서 만들자

가상공간에서 mkdir templates 명령어를 수행한다. 장고는 DIRS에 설정한 디렉토리 외에도 앱 디렉토리 바로 하위에 있는 templates 디렉토리도 템플릿 디렉토리로 인식한다.  즉, pybo 앱의 경우 projects/mysite/pybo/templates 이러한 디렉토리를 생성하면 별다른 설정없이 템플릿 디렉토리로 인식한다.

 

하지만 이처럼 앱 디렉토리 하위에 템플릿 디렉토리를 두는 방법을 권장하지 않는다. 그 이유는 하나의 웹 사이트에서 여러 앱을 사용할 때 여러 앱의 화면을 구성하는 템플릿은 한 디렉토리에 모아 관리하는 편이 여러모로 좋다. 그러므로 pybo 앱은 템플릭 디렉토리로 projects/mysite/pybo/templates 가 아닌 /projects/mysite/templates/pybo 디렉토리를 사용한다. 그리고 공통으로 사용하는 템플릿은 projects/mysite/templates 위치에 저장한다.

모든 앱이 공통으로 사용할 템플릿 디렉토리 - projects/mysite/templates
pybo 앱이 사용할 템플릿 디렉토리 - projects/mysite/templates/pybo
common 앱이 사용할 템플릿 디렉토리 - projects/mysite/templates/common

 

[템플릿 파일]

 

이제 템플릿 파일을 만들어 보자. render 함수에서 사용한 템플릿 파일명은 pybo/question_list.html 이다.

따라서 question_list.html 파일은 projects/mysite/templates/pybo/question_list.html 경로에 작성해야 한다.

그 후 pybo/question_list.html 파일을 다음과 같이 작성하자.

오타가 있다 />pybo/ 가아니라 /pybo/ 이다.

템플릿을 보면 {% 와 %} 로 둘러쌓인 문장이 있는데 이것을 템플릿 태그라고 한다. 여기에 사용된 템플릿 태그들을 하나씩 살펴보자면

{% if question_list %} : question_list 가 있다면
{% for question in question_list %} : question_list를 순회하며 순차적으로 하나씩 question 에 대입
{{ question.id }} : for 문에 의해 대입된 question 객체의 id 번호를 출력
{{ question.subject }} : for 문에 의해 대입된 question 객체의 제목을 출력

템플릿에서 사용한 question_list 는 render 함수로 전달한 질문 목록 데이터이다.

 

[템플릿 태그]

 

장고에서 사용하는 템플릿 태그는 3가지 유형만 알면된다.

 

1. 분기

{% if 조건문1 %}
    <p>조건문1에 해당되는 경우</p>
{% elfi 조건문2 %}
    <p>조건문2에 해당되는 경우</p>
{% else %}
    <p>조건문1, 2 에 모두 해당되지 않는 경우</p>
{% endif %}

파이썬의 if 문과 비슷하다. 다만 항상 {% endif %} 태그로 닫아주는것을 잊지 말자.

 

2. 반복

{% for item in list %}
    <p>순서 : {{ forloop.counter }} </p>
    <p>{{ item }}</p>
{% endfor %}
forloop.counter : 루프내의 순서로 1부터 표시
forloop.counter0 : 루프내의 순서로 0부터 표시
forloop.first : 루프의 첫번째 순서인 경우 True
forloop.last : 루프의 마지막 순서인 경우 True

 

3. 객체 출력

{{ 객체 }}

ex) {{ item }}

 

객체에 속성이 있는 경우는 파이썬과 동일한 방법으로 도트(.) 문자를 이용하여 표시하면 된다.

{{ 객체.속성 }}

ex) {{ question.id }}, {{ question.subject }}

 

[테스트]

 

템플릿 디렉토리 추가 후에는 로컬 서버를 재시작 해야 한다.

여기까지 수정하고 로컬 서버를 재시작 후 http://localhost:8000/pybo/ 페이지를 요청하면 다음과 같은 화면이 나온다.

이전에 등록한 질문 2건이 조회된다. 이제 질문 목록 중 한개를 선택해보면

%3EPybo랑 />pybo/ 라고 나온것은 무시하자. 오타이다.

이러한 오류가 나온다. http://localhost:8000/pybo/2/ 에 대한 URL 매핑이 아직 없기 때문이다.

 저 URL 의 의미는 id 값이 2 인 Question 을 상세 조회한다는 뜻이다. 이 URL 이 작동할 수 있도록 pybo/urls.py 파일을 수정하자.

추가한 라인의 뜻은 http://localhost:8000/pybo/2/ 페이지가 요청되면 여기에 등록한 매핑 룰에 의해 http://localhost:8000/pybo/<int:question_id/> 가 적용되어 question_id 에 2가 저장되고 views.detail 함수도 실행된다.

 

이제 위의 URL 매핑 규칙에 의해 실행되는. views.detail 함수를 만들어야 한다. pybo/views.py 파일에 detail 함수를 추가하자.

index 함수와 크게 다른 부분은 없다. 다만 detail 함수 호출시 전달되는 매개변수가 request 외에 question_id 가 추가되었다. 매개변수 request_id 에는 URL 매핑시 저장된 question_id 가 전달된다.

 

 

detail 함수에서 사용할 pybo/question_detail.html 템플릿도 작성해야한다.

projects/mysite/templates/pybo/question_detail.html 을 만들고 다음과 같이 작성하자.

{{ question.subject }} 과 {{ question.content }}의 question은 detail 함수에서 템플릿에 context 변수로 전달된 Question 모델 객체이다.

 

여기까지 했다면 다시 페이지를 요청해보자.

질문 상세 기능을 만들었다!

 

 

[오류 페이지]

 

이제는 오류 페이지를 만들어보자.

http://localhost:8000/pybo/30/ 페이지를 요청했을때의 모습이다. DoesNotExist 오류가 발생한다. 이 오류는 전달된 question_id 가 30이기 때문에 Question.object.get(id=30)이 호출되어 발생한 오류이다. 이때 브라우저에 전달되는 오류코드는 500이다.

 

이런식으로 없는 데이터를 요청할 경우 500 오류 페이지 보다는 "Not Found(404)" 페이지를 리턴하는것이 좋다.

 

[HTTP 주요 응답 코드의 종류]
오류코드 200 = 성공
오류코드 500 = 서버오류(Internal Server Error)
오류코드 404| = 서버가 요청한 페이지를 찾을수 없음(Not Found)

방금 처럼 없는 데이터를 요청할 경우 404 페이지를 출력하도록 detail 함수를 수정해보자.

수정한 pk=question_id 에서 pk 는 Question 모델의 기본 키(Primary Key) 에 해당하는 값이다. 이렇게 수정하고 다시 페이지를 요청해보자.

404 오류 페이지 출력으로 변경되었다.

'Django > 따라하는 장고' 카테고리의 다른 글

10. 답변 등록하기  (0) 2022.10.22
9. URL 별칭  (0) 2022.10.20
7. 장고 관리자  (1) 2022.10.17
6. 모델 사용법  (0) 2022.10.13
5. 장고 모델 작성법  (0) 2022.10.13