Django分页教程及示例
推荐超级课程:
@TOC
Django的分页模块允许你将大量数据分割成更小的块(页面)。这对于以可管理的方式显示项目列表,如博客文章或产品,特别有用。让我们深入探讨如何逐步实现分页。
- 什么是分页? ======================
分页是将大型数据集分成更小的集合或页面的过程。每个页面包含有限数量的项目,用户可以浏览不同的页面。
- 设置Django项目 =======================
首先,创建并激活虚拟环境,以及创建Django项目和应用,如果你还没有的话。
mkdir myproject
cd myproject
python -m venv venv # 创建虚拟环境
source venv\bin\activate # 激活虚拟环境
django-admin startproject myproject .
python manage.py startapp myapp
更新settings.py
中的INSTALLED_APPS
以包含应用:
INSTALLED_APPS = [
# 其他应用
'myapp',
]
- 设置模型 ====================
让我们创建一个简单的Post
模型来显示分页内容。
# myapp/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
def __str__(self):
return self.title
现在,进行迁移并迁移模型:
python manage.py makemigrations
python manage.py migrate
你也可以在Django管理面板中添加一些示例数据或使用shell
:
python manage.py shell
from myapp.models import Post
for i in range(1, 101):
Post.objects.create(title=f"文章{i}", content=f"文章{i}的内容")
- 创建带分页的视图 ==================================
Django提供了Paginator
类来处理分页。让我们创建一个视图来对Post
对象进行分页。
# myapp/views.py
from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Post
def post_list(request):
posts = Post.objects.all()
paginator = Paginator(posts, 10) # 每页显示10篇帖子。
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'myapp/post_list.html', {'page_obj': page_obj})
在这里,我们使用Paginator
将Post
对象分成每页10篇的页面。我们还从URL查询参数中获取page_number
(例如?page=2
等),并将page_obj
传递给模板。
- 在模板中使用分页 ================================
现在,让我们创建一个模板来显示分页后的帖子。
<!-- myapp/templates/myapp/post_list.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分页帖子列表</title>
</head>
<body>
<h1>分页帖子</h1>
<ul>
{% for post in page_obj %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
<div class="pagination">
<span>
第{{ page_obj.number }}页,共{{ page_obj.paginator.num_pages }}页
</span>
{% if page_obj.has_previous %}
<a href="?page=1">首页</a>
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<strong>{{ num }}</strong>
{% else %}
<a href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
<a href="?page={{ page_obj.paginator.num_pages }}">末页</a>
{% endif %}
</div>
</body>
</html>
说明:
for
循环显示page_obj
中的每个帖子标题。- 我们创建分页控件,显示:
- 如果有上一页,则显示首页和上一页按钮。
- 页码和当前页高亮显示。
- 如果有更多页,则显示下一页和末页按钮。
处理边缘情况 ======================
空页:当用户请求不存在的页面时(例如
page=1000
),Django会引发EmptyPage
异常。你可以在视图中处理这个情况:
# myapp/views.py
from django.core.paginator import EmptyPage, PageNotAnInteger
def post_list(request):
posts = Post.objects.all()
paginator = Paginator(posts, 10)
page_number = request.GET.get('page')
try:
page_obj = paginator.get_page(page_number)
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
return render(request, 'myapp/post_list.html', {'page_obj': page_obj})
2. 性能考虑:在处理大型数据集时,分页查询可能会变得缓慢。考虑使用 select_related
或 prefetch_related
来减少在处理相关模型时的数据库访问次数。
- 最终示例 ================
让我们把所有内容整合起来:
- 模型:
Post
模型被定义用于存储文章标题和内容。 - 视图:
post_list
视图使用 Django 的分页功能将文章分为每页10篇。 - 模板:模板显示文章并包含分页控制,带有用于在页面间导航的链接。
完整代码示例:
- 模型(
models.py
):
# myapp/views.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
def __str__(self):
return self.title
- 视图(
views.py
):
# myapp/views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
from .models import Post
def post_list(request):
posts = Post.objects.all()
paginator = Paginator(posts, 10)
page_number = request.GET.get('page')
try:
page_obj = paginator.get_page(page_number)
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
return render(request, 'myapp/post_list.html', {'page_obj': page_obj})
- 模板(
post_list.html
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分页文章列表</title>
</head>
<body>
<h1>分页文章</h1>
<ul>
{% for post in page_obj %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
<div class="pagination">
<span>
第 {{ page_obj.number }} 页,共 {{ page_obj.paginator.num_pages }} 页
</span>
{% if page_obj.has_previous %}
<a href="?page=1">首页</a>
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<strong>{{ num }}</strong>
{% else %}
<a href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
<a href="?page={{ page_obj.paginator.num_pages }}">末页</a>
{% endif %}
</div>
</body>
</html>
结论
本教程涵盖了 Django 分页的基础知识及示例。分页在处理大型数据集时对于改善用户体验至关重要。感谢您的阅读!如果您发现任何错误或有改进建议,请在下方留言。