Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Baidu-style Pagination Implementation for Django

Notes 3

Create a reusable pagination helper module pagination.py:

from django.utils.safestring import mark_safe

class BaiduPagination:
    """
    Baidu-style pagination generator for Django
    current: Current active page number
    total_items: Total number of records to paginate
    items_per_page: Number of records to display per page
    max_display_pages: Maximum number of page links to show in the navigation bar
    """
    def __init__(self, current, total_items, items_per_page=5, max_display_pages=6):
        self.current = int(current)
        self.total_items = total_items
        self.items_per_page = items_per_page
        self.max_display_pages = max_display_pages

    @property
    def slice_start(self):
        return (self.current - 1) * self.items_per_page

    @property
    def slice_end(self):
        return self.current * self.items_per_page

    @property
    def total_pages(self):
        full_pages, remainder = divmod(self.total_items, self.items_per_page)
        if remainder:
            full_pages += 1
        return full_pages

    def render_html(self, base_url):
        nav_elements = []

        # Add first page link
        first_page = f'<li><a class="page-link" href="{base_url}p={1}">First</a></li>'
        nav_elements.append(first_page)

        # Calculate range of page links to display
        if self.total_pages < self.max_display_pages:
            start = 1
            end = self.total_pages + 1
        else:
            # Adjust start and end to keep current page centered
            half_display = (self.max_display_pages + 1) // 2
            if self.current <= half_display:
                start = 1
                end = self.max_display_pages + 1
            else:
                start = self.current - (self.max_display_pages - 1) // 2
                end = self.current + half_display
                # Don't go over total pages
                if end > self.total_pages:
                    end = self.total_pages + 1
                    start = self.total_pages - self.max_display_pages + 1

        # Previous page link
        if self.current == 1:
            prev_link = '<li><a class="page-link" href="javascript:void(0);" style="display: none">Previous</a></li>'
        else:
            prev_link = f'<li><a class="page-link" href="{base_url}p={self.current - 1}">Previous</a></li>'
        nav_elements.append(prev_link)

        # Generate individual page links
        for page_num in range(int(start), int(end)):
            if page_num == self.current:
                link_html = f'<li class="active"><a class="page-link" href="{base_url}p={page_num}">{page_num}</a></li>'
            else:
                link_html = f'<li><a class="page-link" href="{base_url}p={page_num}">{page_num}</a></li>'
            nav_elements.append(link_html)

        # Next page link
        if self.current == self.total_pages:
            next_link = '<li><a class="page-link" href="javascript:void(0);" style="display: none">Next</a></li>'
        else:
            next_link = f'<li><a class="page-link" href="{base_url}p={self.current + 1}">Next</a></li>'
        nav_elements.append(next_link)

        # Add last page link
        last_page = f'<li><a class="page-link" href="{base_url}p={self.total_pages}">Last</a></li>'
        nav_elements.append(last_page)

        # Add record count summary
        summary = f'<span style="display: inline-block; margin-top: 10px; margin-left: 15px;">Total {self.total_items} records, {self.total_pages} pages, {self.items_per_page} per page, current page {self.current}</span>'
        nav_elements.append(summary)

        return mark_safe("".join(nav_elements))

Add the demo vieew in your app's views.py:

from django.shortcuts import render
from . import pagination

def pagination_demo(request):
    # Sample dataset for demonstration
    product_list = ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig', 'grape', 'honeydew', 'kiwi']
    # Get current page from request query parameters
    current_page = request.GET.get('p', 1)
    # Initialize pagination instance
    paginator = pagination.BaiduPagination(current_page, len(product_list), items_per_page=2, max_display_pages=4)
    # Slice dataset for current page
    current_page_data = product_list[paginator.slice_start:paginator.slice_end]
    # Generate pagination navigation HTML
    pagination_html = paginator.render_html('/demo/pagination/?')
    return render(request, 'pagination_demo.html', {'page_data': current_page_data, 'pagination_html': pagination_html})

Create the template file templates/pagination_demo.html:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pagination Demo</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <style>
        .item-list li {float: left; margin: 5px 10px;}
    </style>
</head>
<body>
    <ul class="item-list">
        {% for item in page_data %}
        <li>{{ item }}</li>
        {% endfor %}
    </ul>
    <div style="clear: both; margin-left: 270px; margin-top: 20px;">
        <ul class="pagination">
            {{ pagination_html }}
        </ul>
    </div>
</body>
</html>

Register the URL route in you're app's urls.py:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^pagination/$', views.pagination_demo),
]

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.