템플릿 필터란 템플릿 태그에서 | 문자 뒤에 사용하는 필터를 말한다. 예를 들어 None 대신 공백 문자열을 보여주기 위해 사용하던 default_if_none과 같은 것을 템플릿 필터라고 한다.
항상 1로 시작하는 게시물 번호 문제 해결하기
파이보 질문목록 화면을 유심히 보면 페이지마다 게시물 번호가 항상 1부터 시작되는 문제가 있다. 이 문제를 템플릿 필터를 사용하여 해결해 보자.
(1단계) 게시물 번호 공식 만들기
만약 질문 게시물이 12개라면 1페이지에는 역순으로 12~3번째 게시물이, 2페이지에는 2~1번째 게시물이 표시돼야 한다. 질문 게시물의 번호를 역순으로 정렬하면 다음과 같은 공식을 적용해야 한다.
◆ 게시물 일련번호 공식
일련번호 = 전체 개시물 개수 - 시작 인덱스 - 현재 인덱스 + 1
☞ 시작 인덱스: 페이지당 시작되는 게시물의 시작번호를 의미
예) 페이지당 게시물을 10건씩 보여준다면 1페이지의 시작 인덱스는 1, 2페이지의 시작 인덱스는 11이 된다.
☞ 현재 인덱스: 페이지에 보이는 게시물 개수만큼 0부터 1씩 증가되는 번호
따라서 전체 게시물 개수가 12개이고 페이지당 10건씩 게시물을 보여준다면
1페이지의 경우는
12-1-(0~9반복) +1 이 되어 12~3까지 표시되고,
2페이지의 경우는
12-11-(0~1반복)+1 이 되어 2~1이 표시될 것이다.
템플릿에서 이 공식을 적용하려면 빼기 기능이 필요하지만 장고에는 빼기 필터가 없다. 그래서 빼기 필터를 만들 것이다.
(2단계) 템플릿 필터 디렉터리 만들기
템플릿 필터 함수는 템플릿 필터 파일을 작성한 다음에 정의해야 한다. 템플릿 필터 파일은 템플릿 파일이나 스태틱 파일과 마찬가지로 pybo/templatetags 디렉터리를 새로 만들어 저장해야 한다.
저장 경로: D:\projects\mysite\pybo\templatetags
pybo/templatetags 디렉터리는 반드시 앱 디렉터리 아래에 생성해야 한다. mysite 디렉터리 아래에 만들면 안 된다!
(mysite) D:\projects\mysite>cd pybo (mysite) D:\projects\mysite\pybo>mkdir templatetags (mysite) D:\projects\mysite\pybo> |
(3단계) 템플릿 필터 작성하기
pybo_filter.py 파일을 만든 후 템플릿 필터 함수를 다음과 같이 작성하자.
# D:\projects\mysite\pybo\templatetags\pybo_filter.py (New) from django import template register = template.Library() @register.filter def sub(value, arg): return value - arg |
템플릿 필터 함수를 만드는 방법은 무척 간단하다. sub 함수에 @register.filter 라는 애너테이션을 적용하면 템플릿에서 해당 함수를 필터로 사용할 수 있게 된다.
(4단계) 템플릿 필터 사용하기
템플릿 필터 함수를 템플릿에 사용해 보자. 내가 직접 만든 템플릿 필터를 사용하려면 템플릿 파일 맨 위에 {% load pybo_filter %} 와 같이 템플릿 필터 파일을 로드해야 한다. 만약에 템플릿 파일 맨 위에 extends 문이 있으면 load문은 extends 문 다음에 위치해야 한다.
템플릿 파일에서 템플릿 필터 파일 로드 예)
{% load pybo_filter %}
질문목록 템플릿에 템플릿 필터 로드 후 일련번호를 적용한다.
# D:\projects\mysite\templates\pybo\question_list.html {% extends 'base.html' %} {% load pybo_filter %} {% block content %} <div class="container my-3"> <table class="table"> <thead> <tr class="thead-dark"> <th>번호</th> <th>제목</th> <th>작성일시</th> </tr> </thead> <tbody> {% if question_list %} {% for question in question_list %} <tr> <td> <a href="{% url 'pybo:detail' question.id %}"> {{ question.subject }} </a> </td> <td>{{ question.create_date }}</td> </tr> {% endfor %} {% else %} <tr> <td colspan="3">질문이 없습니다. </td> </tr> {% endif %} </tbody> </table> <!-- 페이징 처리 시작 --> (... 생략...) </div> {% endblock %} |
<td>{{ forloop.counter }}</td> 에서 forloop.counter 부분을 question_list.paginator.count|sub:question_list.start_index|sub:forloop.counter0|add:1 으로 변경했다.
공식 요소 | 설명 |
question_list.paginator.count | 전체 게시물 개수 |
question_list.start_index | 시작 인덱스(1부터 시작) |
forloop.counter0 | 루프 내의 현재 인덱스 (forloop.counter0는 0부터, forloop.counter는 1부터 시작) |
코스 수정 후 서버를 재시작하여 일련번호를 확인해 보면 항상 1부터 시작했던 문제가 해결되었음을 확인할 수 있다.
질문에 달린 답변 개수 표시하기
답변 개수는 게시물 제목 바로 우측에 표시하자.
# D:\projects\mysite\templates\pybo\question_list.html {% extends 'base.html' %} {% load pybo_filter %} {% block content %} <div class="container my-3"> <table class="table"> <thead> <tr class="thead-dark"> <th>번호</th> <th>제목</th> <th>작성일시</th> </tr> </thead> <tbody> {% if question_list %} {% for question in question_list %} <tr> <td>{{ question_list.paginator.count|sub:question_list.start_index|sub:forloop.counter0|add:1 }}</td> <td> <a href="{% url 'pybo:detail' question.id %}"> {{ question.subject }} </a> <!-- 답변 개수 표시 --> {% if question.answer_set.count > 0 %} <span class="text-danger small ml-2"> {{ question.answer_set.count }} </span> {% endif %} </td> <td>{{ question.create_date }}</td> </tr> {% endfor %} {% else %} <tr> <td colspan="3">질문이 없습니다. </td> </tr> {% endif %} </tbody> </table> (.. 생략...) </div> {% endblock %} |
{% if question.answer_set.count > 0 %} 로 답변이 있는 경우를 검사하고, {{ question.answer_set.count }} 로 답변 개수를 표시했다.
여기까지.
댓글