질문 목록 페이지는 아직 페이징 처리가 안되어 있기 때문에 만약 300개의 게시물을 작성하면 한 페이지에 300개의 게시물이 모두 한꺼번에 표시된다. 이 문제를 해결해보자.
일단 테스트를 할 수 있도록 테스트데이터를 만들자. 다음 명령어로 장고 쉘을 실행하자.
여기서 질문 데이터를 생성하기 위한 모듈을 import 한후 for 문을 이용해 300개의 테스트 데이터를 생성하자.
그리고 장고셸을 종료하고 테스트를 확인해보자.
300개 이상의 질문들이 한 페이지에 전부 보여진다. 반드시 페이징이 필요한 이유이다.
[Paginator]
장고에서 페이징을 위한 클래스는 Paginator 이다. 이 클래스를 이용해 index 함수에 페이징 기능을 적용하자.
projects\mysite\pybo\views.py 파일을 다음과 같이 수정하자.
page = request.GET.get('page', '1') 은 http://localhost:8000/pybo/?page=1 처럼 GET 방식으로 호출된 URL 에서 page 값을 가져올 때 사용한다. 만약 http://localhost:8000/pybo/ 처럼 page 값 없이 호출된 경우에는 디폴트로 1이라는 값을 설정한다.
paginator = Pagiantor(question_list, 10) 에서 첫 번째 파라미터 question_list 는 게시물 전체를 의미하는 데이터이고 두번째 파라미터 10은 페이지당 보여줄 게시물의 수이다.
page_obj = paginator.get_page(page) 의 의미는 paginator 를 이용해 요청된 페이지에 해당되는 페이지 객체(page_obj)를 생성했다. 이렇게 하면 장고 내부적으로는 데이터 전체를 조회하지 않고 해당 페이지의 데이터만 조회하도록 쿼리가 변경된다. 쿼리는 웹 서버에 특정한 정보를 보여달라는 웹 클라이언트 요청에 의한 처리이다.
페이징 객체 page_obj 에는 다양한 속성들이 있다.
paginator.count | 전체 게시물 개수 |
paginator.per_page | 페이지당 보여줄 게시물 개수 |
paginator.page_range | 페이지 범위 |
number | 현재 페이지 번호 |
previous_page_number | 이전 페이지 번호 |
next_page_number | 다음 페이지 번호 |
has_previous | 이전 페이지 유무 |
has_next | 다음 페이지 유무 |
start_index | 현재 페이지 시작 인덱스(1부터 시작) |
end_index | 현재 페이지의 끝 인덱스(1부터 시작) |
이 속성들은 템플리에서 페이징을 처리할 때 사용된다.
index 하수에서 pybo/question_list.html 에 전달한 데이터(context)는 다음과 같다.
따라서 질문 목록 템플릿에 전달된 페이징 객체는 question_list 이다.
이제 템플릿을 페이징에 적용하기위해
projects\mysite\templates\pybo\question_list.html 파일을 다음과 같이 수정하자. </table> 태그 바로 밑에 추가하자.
양은 많지만 하나하나 살펴보면 어렵지 않다. 문단별로 살펴보면,
이전 페이지가 있는 경우에는 '이전' 링크가 활성화 되고, 이전 페이지가 없는 경우에는 '이전' 링크가 비활성화 된다.
페이지 리스트를 루프 돌면서 해당 페이지로 이동할 수 있는 링크를 생성하였다. 이 때 현재 페이지와 같을 경우에는 active 클래스를 적용해 강조표시를 했다.
다음 페이지가 있는 경우에는 '다음' 링크가 활성화 되고, 다음 페이지가 없는 경우에는 '다음' 링크가 비활성화 된다.
위 템플릿에 사용된 주요 페이징 기능을 살펴보자면
기능 | 코드 |
이전 페이지가 있는지 체크 | {% if question_list.has_previous %} |
이전 페이지 번호 | {{ question_list.previous_page_number }} |
다음 페이지가 있는지 체크 | {% if question_list.has_next %} |
다음 페이지 번호 | {{ question_list.next_page_number }} |
페이지 리스트 루프 | {% for page_number in question_list.paginator.page_range %} |
현제 페이지와 같은지 체크 | {% if page_number == question_list.number %} |
그리고 페이지 리스트를 보기 좋게 표시하기 위해 부트스트랩의 pagination 컴포넌트를 이용했다. 템플릿에 사용한 pagination, page-item, page-link 등이 부트스트랩의 pagiantion 컴포넌트의 클래스이다. 컴포넌트란 여러 개의 프로그램 하수들을 모아 하나의 특정한 기능을 수행할 수 있도록 구성한 작은 단위를 말한다. 컴포넌트를 이용하면 소프트웨어 개발을 마치 레고블록을 쌓듯이 조립식으로 쉽게 할 수 있다. 모듈 이라고도 한다.
이제 잘 적용되었는지 확인해보자.
페이징처리는 잘 되었지만 한 페이지에 모든 페이지가 표시되어서 오히려 보기 안좋아 졌다. 해결하기 위해
projects\mysite\templates\pybo\question_list.html 을 다음과 같이 수정하자.
위 코드에서 |add:-5, |add:5 는 템플릿 필터로 각각 -5만큼 빼고 5만큼 더하라는 의미이다.
위 코드는 페이지 르스트가 현재 페이지 기준으로 좌우 5개씩만 보이도록 만든다. 현재 페이지를 의미하는 question_list.number 보다 5만큼 크거나 작은 값만 표시되는것이다.
확인해보면 이제 페이지 번호들이 깔끔하게 나오는것을 확인할 수 있다.
'Django > 따라하는 장고' 카테고리의 다른 글
18. 로그인 기능 (0) | 2022.11.09 |
---|---|
17. 템플릿 필터 및 답변 개수 표시 (0) | 2022.11.07 |
15. 네비게이션 바 (0) | 2022.11.04 |
14. 폼 (1) | 2022.11.03 |
13. 표준 HTML & 템플릿 상속 (0) | 2022.10.31 |