on
[Django] 3 - 2. 페이징
[Django] 3 - 2. 페이징
이전포스트
[Django] 1. 개발 환경 설정 https://wroni.tistory.com/4
[Django] 2 - 1. URL과 View https://wroni.tistory.com/5
[Django] 2 - 2. 모델 https://wroni.tistory.com/6
[Django] 2 - 3. 장고 관리자 https://wroni.tistory.com/7
[Django] 2 - 4. 조회와 템플릿 https://wroni.tistory.com/8
[Django] 2 - 5. URL과 네임스페이스, 2 - 6. 데이터 저장 https://wroni.tistory.com/9
[Django] 2 - 7. 스태틱 https://wroni.tistory.com/10
[Django] 2 - 8. 부트스트랩 https://wroni.tistory.com/11
[Django] 2 - 9. 템플릿 상속 https://wroni.tistory.com/12
[Django] 2 - 10. 폼 https://wroni.tistory.com/13
[Django] 3 - 1. 네비게이션바 https://wroni.tistory.com/14
3 - 2. 페이징
파이보 질문 목록들이 페이징 처리가 안 되어 있기 때문에 게시물 300개를 작성하면 300개를 전부 조회한다.
페이지를 나누어 게시물을 보기 위해 페이징(Paging)을 적용해보자.
1. 대량 테스트 데이터 생성
페이징을 구현하기 전에 300개 대량 테스트 데이터를 만들어서 저장하자.
먼저 장고 셸을 실행한다.
python manage.py shell
from pybo.models import Question from django.utils import timezone for i in range(300): q = Question(subject='테스트 데이터입니다.:[%03d]' % i, content='내용무', create_date=timezone.now()) q.save
이제 장고 셸을 종료하고 웹 서버를 구동시켜서 테스트 데이터가 생성이 되었는지 확인하자.
잘 만들어졌는데... 300개의 게시물이 한 페이지에 다 뜨고 있다. 페이징이 필요해보인다.
2. Paginator
장고에서 페이징을 위해 사용하는 클래스는 Paginator이다. Paginator 클래스를 사용하여 index 함수에 페이징 기능을 적용할 것이다.
파일 : C:\projects\mysite\pybo\views.py
from django.core.paginator import Paginator def index(request): """ pybo 목록 출력 """ # 입력 파라미터 page = request.GET.get('page', '1') #페이지 #조회 question_list = Question.objects.order_by('-create_date') #페이징처리 paginator = Paginator(question_list, 10) #페이지당 10개씩 보여주기 page_obj = paginator.get_page(page) context = {'question_list': page_obj} return render(request, 'pybo/question_list.html', context)
index 함수를 다음과 같이 수정해주면 된다.
page = request.GET.get('page', '1')은 http://localhost:8000/pybo/?page=1처럼 GET 방식으로 호출된 URL에서 page 값을 가져올 때 사용한다.
만약 http://localhost:8000/pybo/처럼 page 값 없이 호출된 경우에는 디폴트로 1이라는 값을 설정한다.
paginator = Paginator(question_list, 10) # 페이지당 10개씩 보여 주기
첫번째 파라미터 question_list는 게시물 전체를 의미하는 데이터이다. 두번째 파라미터 10은 페이지당 보여줄 게시물 개수이다.
page_obj = paginator.get_page(page)
paginator를 이용하여 요청된 페이지(page)에 해당되는 페이징 객체(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부터 시작)
페이징 처리할 때 사용하기 때문에 알아두면 좋다.
3. 템플릿에 페이징 적용
index 함수에서 질문 목록 템플릿(pybo/question_list.html)에 전달한 데이터(context)는 다음과 같다.
context = {'question_list' : page_obj} # question_list는 페이징 객체(page_obj) return render(request, 'pybo/question_list.htm', context)
질문 목록 템플릿에 전달된 페이징 객체는 question_list이다. 이제 페이징 객체 question_list를 이용하여 템플릿에서 어떻게 페이징을 처리하는지 알아볼 것이다.
question_list.html 템플릿 파일 태그 바로 밑에 다음 코드를 추가한다.
파일 : C:\projects\mysite\templates\pybo\question_list.html
{% if question_list.has_previous %} 이전 {% else %} 이전 {% endif %} {% for page_number in question_list.paginator.page_range %} {% if page_number == question_list.number %} {{ page_number }} {% else %} {{ page_number }} {% endif %} {% endfor %} {% if question_list.has_next %} 다음 {% else %} 다음 {% endif %}
이전 페이지가 있는 경우 "이전" 링크가 활성화되게 하고, 이전 페이지가 없는 경우 "이전" 링크가 비활성화되도록 하였다.
다음 페이지의 경우도 같은 방법으로 적용되었다.
페이지 리스트 루프를 돌면서 해당 페이지로 이동할 수 있는 릉크도 생성하였다.
이때 현재 페이지와 같을 경우에는 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.page_range %} 현재 페이지와 같은지 체크 {% if page_number == question_list.number %}
또한 위의 코드에서 페이지 리스트를 보기 좋게 표시하기 위해 부트스트랩의 pagination 컴포넌트를 사용하였다.
pagination, page-item, page-link 등이 부트스트랩 pagination 컴포넌트의 클래스이다.
4. 페이지 리스트
마지막으로 페이징 처리를 위해 템플릿을 수정해야 한다. 이대로 웹 서버를 구동해보면 이동할 수 있는 페이지가 모두 표시가 된다.
어지러워지기 때문에 현재 페이지에서 5만큼 빼고, 5만큼 더해서 좌우 페이지가 5개씩 보이도록 하자.
파일 : C:\project/mysite/templates/pybo/question_list.html
{% for page_number in question_list.paginator.page_range %} {% if page_number >= question_list.number|add:-5 and page_number <= question_list.number|add:5 %} {% if page_number == question_list.number %} ...생략... {% endif %} {% endif %} # 여기 endif 추가 {% endfor %}
여기서 추가할 코드만 보자면,
{% if page_number >= question_list.number|add:-5 and page_number <= question_list.number|add:5 %} (...생략...) {% endif %}
여기서 사용한 |add:-5, |add:5 는 템플릿 필터이다. |add:-5 는 5만큼 뺀다는 의미이고, |add:5는 5만큼 더한다는 의미이다.
결국 위 코드는 페이지 리스트가 현재 페이지 기준으로 좌우 5개씩 보이도록 만든다.
question_list.number보다 5만큼 크거나 작은 값만 표시되도록 만든 것이다.
이제 웹 서버를 구동해서 확인해보자.
의도한대로 잘 나오고 있다.
(ㅠㅠㅠㅠㅠㅠㅠㅠ Flask 때 페이징 구현하기가 그렇게 힘들었는데 이렇게 간단한 거였나...)
※ 본 내용은 django 공부 기록이며, 점프 투 장고를 참고하였습니다.
https://wikidocs.net/book/4223
from http://wroni.tistory.com/15 by ccl(A) rewrite - 2021-12-02 17:00:34