目录
- 1. 对象的方式使用分页组件
- 2. 项目结构
- 3. 编写pagination.py
- 3.1 pagination.py
- 3.2 view.py
- 4. bug修改之:url中搜索关键词q和page
- 4.1 构造url的一个雏形
- 4.2 修改我们的分页组件
- 4.3 搜索小bug
- 5. 应用分页组件,几行代码实现用户管理分页
- 5.1 批量创建用户,增加用户数量
- 5.2 修改user_list.html
- 5.3 修改view.py
- 总结
欢迎关注 『Django 网页Web开发』 系列,持续更新中
欢迎关注 『Django 网页Web开发』 系列,持续更新中
1. 对象的方式使用分页组件
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数中:
def pretty_list(request):
# 1.根据自己的情况去筛选自己的数据
queryset = models.PrettyNum.objects.all()
# 2.实例化分页对象
page_object = Pagination(request, queryset)
context = {
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 生成页码
}
return render(request, 'pretty_list.html', context)
在HTML页面中
{% for obj in queryset %}
{{obj.xx}}
{% endfor %}
<ul class="pagination">
{{ page_string }}
</ul>
2. 项目结构
在app01下新建utils文件夹,新建pagination.py文件
3. 编写pagination.py
- 首先在def __init__获取得到request 和 request, queryset, page_size=10, page_param=“page”, plus=5 等必要数据
- 给必要的数据标注self(成为对象的属性,便于后面对象方法的调用)
- 创建html()函数用于返回生成的html页码相关的代码,可以调用前面定义的self属性
- 上述的大部分操作就是把原来的代码cv到pagination.py,给必要的属性前加上
self.
"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数中:
```python
def pretty_list(request):
# 1.根据自己的情况去筛选自己的数据
queryset = models.PrettyNum.objects.all()
# 2.实例化分页对象
page_object = Pagination(request, queryset)
context = {
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 生成页码
}
return render(request, 'pretty_list.html', context)
在HTML页面中
{% for obj in queryset %}
{{obj.xx}}
{% endfor %}
<ul class="pagination">
{{ page_string }}
</ul>
3.1 pagination.py
import math
from django.shortcuts import render
from django.utils.safestring import mark_safe
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据(根据这个数据给他进行分页处理)
:param page_size: 每页显示多少条数据
:param page_param: 在URL中传递的获取分页的参数,例如:/etty/list/?page=12
:param plus: 显示当前页的 前或后几页(页码)
"""
page = request.GET.get(page_param, "1")
#默认值是字符串的1是为了能够支持更多可能的数据类型,
#可能以后我们封装数据接口的时候不一定是数据类型,
#所以要把转化为int的工作放在下面的代码中
if page.isdecimal():
page = int(page)#转化为int类型
else:
page = 1
self.page = page
self.page_size = page_size # 每一页记录个数
self.start = (page - 1) * page_size # 记录开始的区间
self.end = page * page_size # 记录结束的区间
self.page_queryset = queryset[self.start:self.end] #获取当前页码的数据
#total_count = models.PrettyNum.objects.all().count() # 统计所有数据记录数
total_count = queryset.count()# 统计所有数据记录数
# 页码
self.plus = 5 # 当前页面 前后几页的数值
self.total_page= math.ceil(total_count / 10) # 总共页面数
#绘制html页码的部分用方法html,调用self.属性
def html(self):
page_str_list = []
if self.total_page < 2 * self.plus + 1: # 页面过少,起始和结束页码改为1和总页面数
start_page = 1
end_page = self.total_page
elif self.page < 1 + self.plus: # 避免出现负数页码
start_page = 1
end_page = self.page + self.plus
elif self.page + self.plus > self.total_page: # 避免超过总页数
start_page = self.page - self.plus
end_page = self.total_page # +1是因为range闭区间
else:
start_page = self.page - self.plus # 当前页面
end_page = self.page + self.plus
# 首页
page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))
# 上一页
if self.page <= 1:
prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
else:
prev = '<li><a href="?page={}">上一页</a></li>'.format(self.page - 1)
page_str_list.append(prev)
# for i in range(1, 21):
for i in range(start_page, end_page + 1): # (306/10)=30.6->向上取整31 ->因为range右边闭区间还要+1
if i == self.page: # 如果是当前所在页面,添加激活样式
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i) # 生成多行页码li
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i) # 生成多行页码li
page_str_list.append(ele) # 添加到一个列表中
# 下一页
if self.page < self.total_page: # 判断是否超过总页数
next = '<li><a href="?page={}">下一页</a></li>'.format(self.page + 1)
else:
next = '<li><a href="?page={}">下一页</a></li>'.format(self.total_page)
page_str_list.append(next)
# 尾页
page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(self.total_page))
# 分页搜索框
search_string = '''
<form method="get">
<div class="input-group" style="width:200px">
<input type="text" name="page" class="form-control" value="" placeholder="页码">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">跳转</button></span>
</div>
</form>
'''
page_str_list.append(search_string)
# page_string = "".join(page_str_list) # 用""分隔符将列表页码的代码连接形成的字符串,需要加个安全信任才能变成html
page_string = mark_safe("".join(page_str_list)) # 用""分隔符将列表页码的代码连接形成的字符串,需要加个安全信任才能变成html
return page_string
3.2 view.py
以后其他页面使用分页功能也只需要page_object = Pagination(request, queryset)
即可
def pretty_list(request):
""" 靓号列表 """
## 随机创建若干数据,写好后f5刷新一下列表生效后注释掉这些代码
# for i in range(300):
# models.PrettyNum.objects.create(mobile=random.randint(13000000000,19000000000),price=random.randint(1,1000),level=random.randint(1,4),status=random.randint(1,2))
data_dict = {}
search_data = request.GET.get("q")
if search_data: # 如果传来的参数非空就搜索,反之显示所有数据
data_dict["mobile__contains"] = search_data # 是否包含指定数据
queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level") # -level表示按照level降序排列显示
page_object = Pagination(request, queryset)
context = {
"search_data": search_data,
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 页码
}
return render(request, 'pretty_list.html', context)
4. bug修改之:url中搜索关键词q和page
我们如何做到同时具有搜索功能和分页功能呢?
分页时候,保留原来的搜索条件
http://127.0.0.1:8000/pretty/list/?q=888
http://127.0.0.1:8000/pretty/list/?page=1
http://127.0.0.1:8000/pretty/list/?q=888&page=23
现在的关键在于如何在代码中实现?q=888&page=23
4.1 构造url的一个雏形
在原来的基础上增加了&page=11
def pretty_list(request):
import copy
query_dict=copy.deepcopy(request.GET)#http://127.0.0.1:8000/pretty/list/?q=1&csdn=2023
print(query_dict.urlencode())#q=1&csdn=2023
query_dict.mutable=True#不修改这个参数就会报错提示无法修改
query_dict.setlist('page',[11])#q=1&csdn=2023&page=11 在原来的基础上增加了&page=11
print(query_dict.urlencode())#讲url打印出来
4.2 修改我们的分页组件
pagination.py核心修改代码1 加入self.query_dict:
def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
import copy
query_dict = copy.deepcopy(request.GET)#复制query
query_dict._mutable = True #设置query可以修改
self.query_dict = query_dict
pagination.py核心修改代码2 把所有page换成参数列表self.query_dict,相当于原来只用page这个参数,现在是page和搜索关键词或者更多参数的一个参数列表:
以首页例子,就是把原来format的内容给到self中设置,然后再用self.query_dict.urlencode()替换原来format中的内容
# 首页
page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))
# 修改后的首页
self.query_dict.setlist(self.page_param, [1])
page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
pagination.py完整代码:
"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数中:
def pretty_list(request):
# 1.根据自己的情况去筛选自己的数据
queryset = models.PrettyNum.objects.all()
# 2.实例化分页对象
page_object = Pagination(request, queryset)
context = {
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 生成页码
}
return render(request, 'pretty_list.html', context)
在HTML页面中
{% for obj in queryset %}
{{obj.xx}}
{% endfor %}
<ul class="pagination">
{{ page_string }}
</ul>
"""
import math
from django.shortcuts import render
from django.utils.safestring import mark_safe
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据(根据这个数据给他进行分页处理)
:param page_size: 每页显示多少条数据
:param page_param: 在URL中传递的获取分页的参数,例如:/etty/list/?page=12
:param plus: 显示当前页的 前或后几页(页码)
"""
import copy
query_dict = copy.deepcopy(request.GET)#复制query
query_dict._mutable = True #设置query可以修改
self.query_dict = query_dict
self.page_param = page_param # 获取分页的参数,在分页组件中是 "page"
page = request.GET.get(page_param, "1")
#默认值是字符串的1是为了能够支持更多可能的数据类型,
#可能以后我们封装数据接口的时候不一定是数据类型,
#所以要把转化为int的工作放在下面的代码中
if page.isdecimal():
page = int(page)#转化为int类型
else:
page = 1
self.page = page
self.page_size = page_size # 每一页记录个数
self.start = (page - 1) * page_size # 记录开始的区间
self.end = page * page_size # 记录结束的区间
self.page_queryset = queryset[self.start:self.end] #获取当前页码的数据
#total_count = models.PrettyNum.objects.all().count() # 统计所有数据记录数
total_count = queryset.count()# 统计所有数据记录数
# 页码
self.plus = 5 # 当前页面 前后几页的数值
self.total_page= math.ceil(total_count / 10) # 总共页面数
def html(self):
page_str_list = []
if self.total_page < 2 * self.plus + 1: # 页面过少,起始和结束页码改为1和总页面数
start_page = 1
end_page = self.total_page
elif self.page < 1 + self.plus: # 避免出现负数页码
start_page = 1
end_page = self.page + self.plus
elif self.page + self.plus > self.total_page: # 避免超过总页数
start_page = self.page - self.plus
end_page = self.total_page # +1是因为range闭区间
else:
start_page = self.page - self.plus # 当前页面
end_page = self.page + self.plus
# 首页
self.query_dict.setlist(self.page_param, [1])
page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
# 上一页
if self.page <= 1:
self.query_dict.setlist(self.page_param, [1])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.page - 1])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(prev)
# for i in range(1, 21):
for i in range(start_page, end_page + 1): # (306/10)=30.6->向上取整31 ->因为range右边闭区间还要+1
if i == self.page: # 如果是当前所在页面,添加激活样式
self.query_dict.setlist(self.page_param, [i])
ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(),i) # 生成多行页码li
else:
self.query_dict.setlist(self.page_param, [i])
ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(),i) # 生成多行页码li
page_str_list.append(ele) # 添加到一个列表中
# 下一页
if self.page < self.total_page: # 判断是否超过总页数
self.query_dict.setlist(self.page_param, [self.page + 1])
next = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page])
next = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(next)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page])
page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
# 分页搜索框
search_string = '''
<form method="get">
<div class="input-group" style="width:200px">
<input type="text" name="page" class="form-control" value="" placeholder="页码">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">跳转</button></span>
</div>
</form>
'''
page_str_list.append(search_string)
# page_string = "".join(page_str_list) # 用""分隔符将列表页码的代码连接形成的字符串,需要加个安全信任才能变成html
page_string = mark_safe("".join(page_str_list)) # 用""分隔符将列表页码的代码连接形成的字符串,需要加个安全信任才能变成html
return page_string
4.3 搜索小bug
搜索框出现None
原因:没有给搜索关键词q设置默认值
search_data = request.GET.get("q")
# 将上一行替换为下面的代码即可
search_data = request.GET.get("q","")
5. 应用分页组件,几行代码实现用户管理分页
5.1 批量创建用户,增加用户数量
因为用户表有个创建时间,会有时区问题,需要先修改setting.py中的设置
Django项目中设置USE_TZ=False
for i in range(300):
models.UserInfo.objects.create(name="张龙分身{}".format(i),password="123456",age=1,account=1,gender=1,create_time="2023-03-15 10:00:17.000000", depart_id=1)
5.2 修改user_list.html
放入
<ul class="pagination">
{{ page_string }}
</ul>
完整代码:
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a class="btn btn-success" href="/pretty/add/">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建靓号
</a>
<div style="float: right;width: 300px;">
<form method="get">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search for..."
value="{{ search_data }}">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
靓号列表
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.mobile }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_level_display }}</td>
<td>{{ obj.get_status_display }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/pretty/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/pretty/{{ obj.id }}/delete/">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="clearfix">
<ul class="pagination">
{{ page_string }}
</ul>
</div>
</div>
{% endblock %}
5.3 修改view.py
def user_list(request):
""" 用户管理 """
# 获取所有用户列表 [obj,obj,obj]
queryset = models.UserInfo.objects.all()
page_object = Pagination(request, queryset, page_size=5)
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.html(),
}
return render(request, 'user_list.html', context)
总结
大家喜欢的话,给个👍,点个关注!给大家分享更多有趣好玩的Python 网页Web开发知识!
版权声明:
发现你走远了@mzh原创作品,转载必须标注原文链接
Copyright 2023 mzh
Crated:2023-3-1
欢迎关注 『Django 网页Web开发』 系列,持续更新中
欢迎关注 『Django 网页Web开发』 系列,持续更新中
『01. 安装配置Django』
『02. 创建并运行一个Django项目』
『03. 初识Django』
『04. 请求和响应,网页跳转重定向,实战简易表单模拟登陆』
『05. 数据库操作,实战用户管理』
『06. 报错:You have 26 unapplied migration(s). Your project may not work properly until you apply the migra』
『07. 模板语法』
『08. 实战项目:部门和员工管理系统(01)』
『09. 实战项目:员工编辑删除功能与靓号管理(02)』
『10. 实战项目:靓号搜索功能(03)』
『11. 实战项目:分页与页码跳转功能(04)』
『12. 实战项目:分页组件的封装 面向接口编程(05)』
『13. 实战项目:添加用户时的时间选择组件(06)』
『14. 实战项目:一些面向对象的代码结构优化(07)』
『15. 实战项目:管理员增删改查,md5密码和密码重置(08)』
『16. 实战项目:BootStrap类的进一步优化(09)』
『17. 实战项目:login业务涉及cookie、session、中间件(10)』
『18. 实战项目:登录时的验证码(11)』
『19. 实战项目:初识Ajax请求(12)』
『20. 实战项目:Ajax实战之订单管理与弹出对话框(13)』
『21. 实战项目:echart数据图表(14)』
『22. 实战项目:简单的文件上传(15)』
『23. 实战项目:Excel和form和moudleForm的文件上传(16)』
【更多内容敬请期待】