Django 페이지네이션 구현 방법

  1. 각 함수 및 템플릿에 페이지네이션 코드 추가하기

상황: 각 페이지에서 페이지네이션 외에 분류, 정렬 등 다른 매개변수를 사용해야 하는 경우, 캡슐화된 라이브러리를 사용하는 것은 권장하지 않습니다.

1단계: 페이지네이션이 필요한 views에 다음 코드를 추가합니다:

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage

def get_user_courses(request):
    user_courses = UserCourse.objects.filter(study_man=request.user)
    course_list = [item.study_course for item in user_courses]
    
    # 페이지네이션 처리 코드
    page_num = request.GET.get('page', '1')
    paginator = Paginator(course_list, 8)
    
    try:
        page_obj = paginator.page(page_num)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)
    
    return render(request, 'users/usercenter-mycourse.html', {
        'course_list': course_list,
        'page_obj': page_obj,
        'type': 'course'
    })

2단계: 템플릿에 다음 HTML 코드를 추가합니다:

<!-- 기존 루프: 모든 데이터 반환 -->
{% for course in course_list %}

<!-- 다음과 같이 변경 -->
{% for course in page_obj %}

<!-- 페이지네이션 영역에 추가 -->
<div class="pageturn">
     {% if page\_obj.has\_previous %} - [이전 페이지](<?page={{ page_obj.previous_page_number }}>)
 {% endif %} {% for num in page\_obj.paginator.page\_range %} {% if num == page\_obj.number %} - [{{ num }}](<?page={{ num }}>)
 {% else %} - [{{ num }}](<?page={{ num }}>)
 {% endif %} {% endfor %} {% if page\_obj.has\_next %} - [다음 페이지](<?page={{ page_obj.next_page_number }}>)
 {% endif %} 
</div>

이렇게 하면 기본적인 페이지네이터가 완성됩니다. 하지만 대부분의 경우 웹사이트에서 페이지네이션 시 정렬과 분류가 필요합니다. 이때 views에서 정렬, 분류 코드를 페이지네이션 코드 전에 작성해야 하며, 페이지네이션 시 정렬과 분류 값이 유지되도록 템플릿에 전달해야 합니다.

def course_list(request):
    all_courses = CourseInfo.objects.all().order_by('-add_time')
    popular_courses = all_courses.order_by('-love_num')[:3]
    current_sort = 'add_time'
    
    # 분류 및 정렬 작업은 페이지네이션 전에 처리
    current_sort = request.GET.get('sort')
    if not current_sort:
        current_sort = 'add_time'
    
    page_num = request.GET.get('page', '1')
    keywords = request.GET.get('keywords', '')
    
    if keywords:
        all_courses = all_courses.filter(
            Q(name__icontains=keywords) | 
            Q(desc__icontains=keywords) | 
            Q(detail__icontains=keywords)
        )
    
    if current_sort:
        all_courses = all_courses.order_by('-' + current_sort)
    
    paginator = Paginator(all_courses, 9)
    
    try:
        page_obj = paginator.page(page_num)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)
    
    # 정렬 및 분류 값을 템플릿에 전달해야 페이지네이션 시 유지됨
    return render(request, 'courses/course-list.html', {
        'all_courses': all_courses,
        'popular_courses': popular_courses,
        'base_type': 'course',
        'current_sort': current_sort,
        'page_obj': page_obj,
        'keywords': keywords
    })

对应的 HTML 也需要 변경됩니다:

 {% if page\_obj.has\_previous %} - [이전 페이지](<?page={{ page_obj.previous_page_number }}&sort={{ current_sort }}>)
 {% endif %} {% for num in page\_obj.paginator.page\_range %} {% if num == page\_obj.number %} - [{{ num }}](<?page={{ num }}&sort={{ current_sort }}>)
 {% else %} - [{{ num }}](<?page={{ num }}&sort={{ current_sort }}>)
 {% endif %} {% endfor %} {% if page\_obj.has\_next %} - [다음 페이지](<?page={{ page_obj.next_page_number }}&sort={{ current_sort }}>)
 {% endif %} 

이렇게 하면 다른 매개변수가 있는 페이지네이션 작업이 완료됩니다.

2. 여러 페이지에서 단순한 페이지네이션만 필요하거나 다른 매개변수가 동일한 경우, 페이지네이션을 클래스로 캡슐화하여 사용할 수 있습니다

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage

class PaginationHelper(Paginator):
    def __init__(self, request, object_list, per_page):
        Paginator.__init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True)
        
        page_num = request.GET.get('page', '1')
        paginator = Paginator(object_list, per_page)
        
        try:
            page_obj = paginator.page(page_num)
        except PageNotAnInteger:
            page_obj = paginator.page(1)
        except EmptyPage:
            page_obj = paginator.page(paginator.num_pages)
        
        page_html_parts = ['<div class="pageturn">'\] if page\_obj.has\_previous(): page\_html\_parts.append( '- [이전 페이지](?page={})
'.format(page\_obj.previous\_page\_number) ) for num in page\_obj.paginator.page\_range: if num == page\_obj.number: page\_html\_parts.append( '- [{}](?page={})
'.format(num, num) ) else: page\_html\_parts.append( '- [{}](?page={})
'.format(num, num) ) if page\_obj.has\_next(): page\_html\_parts.append( '- [다음 페이지](?page={})
'.format(page\_obj.next\_page\_number) ) page\_html\_parts.append('</div>')
        
        self.page_html = ''.join(page_html_parts)
        self.page_obj = page_obj

사용할 때는 필요한 views에서 함수를 가져오기만 하면 됩니다:

# 페이지네이션 기능
# 페이지네이션할 목록을 all_orgs로, 페이지당 데이터 수를 3으로 변경
pagination = PaginationHelper(request, all_orgs, 3)

return render(request, 'orgs/org-list.html', {
    'all_orgs': all_orgs,
    'page_obj': pagination.page_obj,
    'page_html': pagination.page_html
})

해당 HTML에서 한 줄의 코드만 추가하면 됩니다:

<!-- 기존 루프: 모든 데이터 반환 -->
{% for course in course_list %}

<!-- 다음과 같이 변경 -->
{% for course in page_obj %}

<!-- 페이지네이션 영역에 추가 -->
{{ page_html|safe }}

태그: Django pagination backend python web-development

5월 27일 02:15에 게시됨