当平台数据量增长到一定规模,简单的全量查询和页面渲染会导致加载缓慢、用户体验下降。本节课将聚焦分页机制与性能优化,通过Django内置分页工具实现数据分批加载,结合数据库查询优化、缓存策略和前端优化技巧,全面提升系统响应速度,确保平台在数据量增长时仍能保持高效运行。
一、Django分页核心组件与基础实现
分页的核心是将大量数据拆分为多个页面加载,减少单次数据传输量。Django提供了Paginator
和Page
两个核心类,简化分页逻辑实现。
1.1 分页核心组件解析
-
Paginator
类:负责将数据集合分页- 核心参数:
object_list
(需分页的数据,如QuerySet)、per_page
(每页条数) - 核心方法:
page(number)
(获取指定页码的数据页)
- 核心参数:
-
Page
类:表示单个分页页面- 常用属性:
object_list
(当前页数据)、number
(当前页码)、paginator
(关联的Paginator对象) - 常用方法:
has_next()
(是否有下一页)、has_previous()
(是否有上一页)、next_page_number()
/previous_page_number()
(获取下/上一页页码)
- 常用属性:
1.2 服务列表分页实现(传统分页)
以服务列表为例,实现基础分页功能,支持筛选条件与页码联动。
1.2.1 视图层:处理分页逻辑
# services/views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
from .models import Service
def service_list(request):
"""服务列表页:支持分类筛选、关键词搜索和分页"""
# 1. 获取查询参数(分类、搜索关键词、页码)
category = request.GET.get('category', '') # 分类筛选
search_query = request.GET.get('q', '') # 关键词搜索
page_num = request.GET.get('page') # 页码
# 2. 构建基础查询集(只查询活跃服务)
services = Service.objects.filter(is_active=True)
# 3. 应用筛选条件(保留筛选状态,与分页联动)
if category:
services = services.filter(category=category)
if search_query:
services = services.filter(
Q(name__icontains=search_query) | Q(description__icontains=search_query)
)
# 4. 分页处理(每页12条数据,按创建时间倒序)
paginator = Paginator(services.order_by('-created_at'), 12)
try:
services_page = paginator.page(page_num) # 获取指定页数据
except PageNotAnInteger:
services_page = paginator.page(1) # 页码不是整数时返回第1页
except EmptyPage:
services_page = paginator.page(paginator.num_pages) # 页码超出范围时返回最后一页
# 5. 传递数据到模板(包含分页对象和筛选参数)
context = {
'services': services_page, # 分页后的当前页数据
'category_filter': category, # 当前分类筛选条件(用于模板回显)
'search_query': search_query # 当前搜索关键词(用于模板回显)
}
return render(request, 'services/service_list.html', context)
1.2.2 模板层:渲染分页导航
分页导航需支持页码跳转,并保留筛选条件(如分类、搜索关键词):
<!-- templates/services/service_list.html -->
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container my-5">
<!-- 筛选表单(省略,与前几课保持一致) -->
<!-- 服务列表网格 -->
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
{% for service in services %}
<!-- 服务卡片组件(复用前几课的service_card.html) -->
{% include 'services/partials/service_card.html' %}
{% empty %}
<div class="col-12">
<div class="alert alert-info">没有找到匹配的服务</div>
</div>
{% endfor %}
</div>
<!-- 分页导航(当总页数>1时显示) -->
{% if services.paginator.num_pages > 1 %}
<nav class="mt-5">
<ul class="pagination justify-content-center">
<!-- 首页和上一页 -->
{% if services.has_previous %}
<li class="page-item">
<a class="page-link"
href="?page=1{% if category_filter %}&category={
{ category_filter }}{% endif %}{% if search_query %}&q={
{ search_query }}{% endif %}">
首页
</a>
</li>
<li class="page-item">
<a class="page-link"
href="?page={
{ services.previous_page_number }}{% if category_filter %}&category={
{ category_filter }}{% endif %}{% if search_query %}&q={
{ search_query }}{% endif %}">
« 上一页
</a>
</li>
{% endif %}
<!-- 页码列表(只显示当前页附近3页,避免页码过多) -->
{% for num in services.paginator.page_range %}
{% if num == services.number %}
<!-- 当前页 -->
<li class="page-item active">
<span class="page-link">{
{ num }}</span>
</li>
{% elif num > services.number|add:'-3' and num < services.number|add:'3' %}
<!-- 当前页前后3页 -->
<li class="page-item">
<a class="page-link"
href="?page={
{ num }}{% if category_filter %}&category={
{ category_filter }}{% endif %}{% if search_query %}&q={
{ search_query }}{% endif %}">
{
{ num }}
</a>
</li>
{% endif %}
{% endfor %}
<!-- 下一页和末页 -->
{% if services.has_next %}
<li class="page-item"></