Baidu-style Pagination Implementation for Django
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),
]