1from django.conf import settings
2from django.core.paginator import Paginator, Page
3
4
5class EnhancedPaginator(Paginator):
6
7    def __init__(self, object_list, per_page, orphans=None, **kwargs):
8
9        # Determine the page size
10        try:
11            per_page = int(per_page)
12            if per_page < 1:
13                per_page = settings.PAGINATE_COUNT
14        except ValueError:
15            per_page = settings.PAGINATE_COUNT
16
17        # Set orphans count based on page size
18        if orphans is None and per_page <= 50:
19            orphans = 5
20        elif orphans is None:
21            orphans = 10
22
23        super().__init__(object_list, per_page, orphans=orphans, **kwargs)
24
25    def _get_page(self, *args, **kwargs):
26        return EnhancedPage(*args, **kwargs)
27
28
29class EnhancedPage(Page):
30
31    def smart_pages(self):
32
33        # When dealing with five or fewer pages, simply return the whole list.
34        if self.paginator.num_pages <= 5:
35            return self.paginator.page_range
36
37        # Show first page, last page, next/previous two pages, and current page
38        n = self.number
39        pages_wanted = [1, n - 2, n - 1, n, n + 1, n + 2, self.paginator.num_pages]
40        page_list = sorted(set(self.paginator.page_range).intersection(pages_wanted))
41
42        # Insert skip markers
43        skip_pages = [x[1] for x in zip(page_list[:-1], page_list[1:]) if (x[1] - x[0] != 1)]
44        for i in skip_pages:
45            page_list.insert(page_list.index(i), False)
46
47        return page_list
48
49
50def get_paginate_count(request):
51    """
52    Determine the desired length of a page, using the following in order:
53
54        1. per_page URL query parameter
55        2. Saved user preference
56        3. PAGINATE_COUNT global setting.
57
58    Return the lesser of the calculated value and MAX_PAGE_SIZE.
59    """
60    def _max_allowed(page_size):
61        if settings.MAX_PAGE_SIZE:
62            return min(page_size, settings.MAX_PAGE_SIZE)
63        return page_size
64
65    if 'per_page' in request.GET:
66        try:
67            per_page = int(request.GET.get('per_page'))
68            if request.user.is_authenticated:
69                request.user.config.set('pagination.per_page', per_page, commit=True)
70            return _max_allowed(per_page)
71        except ValueError:
72            pass
73
74    if request.user.is_authenticated:
75        per_page = request.user.config.get('pagination.per_page', settings.PAGINATE_COUNT)
76        return _max_allowed(per_page)
77
78    return _max_allowed(settings.PAGINATE_COUNT)
79