from django.db import models
# Create your models here.
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid")
def __str__(self):
return self.name
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
def __str__(self):
return self.name
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
publish=models.ForeignKey(to="Publish",to_field="nid")
authors=models.ManyToManyField(to='Author',)
def __str__(self):
return self.title
指定数据库同步指令:makemigrations和migrate
在应用文件app01下创建一个py文件,名字随意,如init_book_table.py
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day068_model_form_lesson.settings") # 引入django的环境
import django
django.setup() # 运行Django环境,之后可以使用django中的其他文件
from app01 import models
import random
l1 = []
for i in range(1, 81): # 创建100条记录
obj = models.Book(
title='红楼梦第%s回'%i,
price= random.randint(100,200),
publishDate='1998-06-%s'%(random.randint(1,30)),
publish_id=random.randint(1,3),
)
l1.append(obj)
models.Book.objects.bulk_create(l1)
创建好后,直接右键运行即可,就可以用DJango环境执行这段代码,在数据库中创建100天记录。
使用django内置的分页器需要导入分页器类
from django.core.paginator import Paginator,EmptyError # EmptyError是一个没有取到页面的错误
通过给Paginator类传递所有数据的queryset对象,以及每页显示数量来实例化一个paginator对象。这个对象有所有对分页的处理方法。
paginator.count:返回所有记录的总数量
paginator.num_pages:返回分页后的总页数
paginator.page_range:返回分页后的页码范围,一个range对象
all_books = models.Book.objects.all()
paginator = Paginator(all_books,10) # 将所有的book对象传给Paginator生成分页器对象,10表示每一页展示的数据数量
"""paginator对象的属性"""
print("count",paginator.count) # 显示数据总数量 count 83
print("num_pages",paginator.num_pages) # 显示分页后总页数 num_pages 9
print("page_range",paginator.page_range) # 显示页面的范围 page_range range(1, 10)
all_books = models.Book.objects.all()
paginator = Paginator(all_books,10) # 将所有的book对象传给Paginator生成分页器对象,10表示每一页展示的数据数量
"""paginator对象的属性"""
print("count",paginator.count) # 显示数据总数量 count 83
print("num_pages",paginator.num_pages) # 显示分页后总页数 num_pages 9
print("page_range",paginator.page_range) # 显示页面的范围 page_range range(1, 10)
from django.shortcuts import render, redirect, HttpResponse
from utils.modelFormLesson import BookForm
from app01 import models
from django.core.paginator import Paginator,EmptyPage
def show(request):
if request.method == "GET":
all_books = models.Book.objects.all()
paginator = Paginator(all_books,10) # 将所有的book对象传给Paginator生成分页器对象,10表示每一页展示的数据数量
"""paginator对象的属性"""
print("count",paginator.count) # 显示数据总数量 count 83
print("num_pages",paginator.num_pages) # 显示分页后总页数 num_pages 9
print("page_range",paginator.page_range) # 显示页面的范围 page_range range(1, 10)
# """paginator对象的方法"""
# page1 = paginator.page(1) # 获取第一页的所有数据
# print(page1)
# for i in page1:
# print(i)
#
# page_obj = paginator.page(2)
# print("是否有下一页",page_obj.has_next()) # 是否有上一页 True
# print("下一页的页码",page_obj.next_page_number()) # 下一页的页码 3
# print("是否有上一页",page_obj.has_previous()) # 是否有下一页 True
# print("上一页的页码",page_obj.previous_page_number()) # 上一页的页码 1
"""分页逻辑部分"""
current_page_num = request.GET.get("page",1) # 获取请求页面,也就是当前页
current_page_num = int(current_page_num)
all_pages = paginator.num_pages # 分页后的所有页数
try:
current_books = paginator.page(current_page_num) # 获取当前页的所有数据
except EmptyPage:
current_books = paginator.page(paginator.num_pages)
print(">>>>>>>>>>",current_books)
if current_page_num <= 3:
page_range = range(1,6)
elif 3 < current_page_num <= paginator.num_pages - 2:
page_range = range(current_page_num-2,current_page_num+3)
else:
page_range = range(all_pages-4,all_pages+1)
return render(request,"show.html",{"page_range":page_range,"current_books":current_books,"current_page_num":current_page_num})
模板文件show.html
在前端页面注意点:
在实现上一页和下一页的功能时,需要判断当前页是不是最后一页,也就是当前页有没有上一页或下一页。
如果是,那么在a标签中的href属性中不能再使用current_books.next_page_number或current_books.previous_page_number,不然会EmptyError错误。
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
<h1 style="text-align: center">书籍展示页面</h1>
<div class="container-fluid">
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<!--===============================数据展示部分==============================-->
<div style="height: 450px">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>序号</th>
<th>书名</th>
<th>出版日期</th>
<th>价格</th>
<th>出版社</th>
<th>作者</th>
<th>菜单</th>
</tr>
</thead>
<tbody>
{% for book in current_books %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.title }}</td>
<td>{{ book.publishDate|date:"Y-m-d" }}</td>
<td>{{ book.price }}</td>
<td>{{ book.publish }}</td>
<td>
{% for author in book.authors.all %}
{{ author.name }}
{% if forloop.last %}
{% endif %}
{% endfor %}
</td>
<td>
<a href="" class="btn btn-warning btn-xs">编辑</a>
<button class="btn btn-danger btn-xs">删除</button>
<span class="hidden">{{ book.pk }}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!--===============================分页部分==================================-->
<nav aria-label="Page navigation" class="pull-right">
<ul class="pagination">
<!--上一页设置-->
<!--判断是否有上一页,有的话可以点击左箭头跳上一页-->
{% if current_books.has_previous %}
<li>
<a href="{% url 'show' %}?page={{ current_books.previous_page_number }}"
aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<!--没有上一页,让按钮变为disable,不让点击-->
{% else %}
<li class="disabled">
<a aria-label="Previous"> <!--注意第一页没有上一页,所以这里a标签的href属性不能再写了,如果写了,那么current_books.previous_page_number方法会一直报错。-->
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
<!--页面设置-->
{% for page in page_range %}
{% if page == current_page_num %}
<li class="active">
<a href="{% url 'show' %}?page={{ page }}" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% else %}
<li>
<a href="{% url 'show' %}?page={{ page }}" aria-label="Previous">
<span aria-hidden="true">{{ page }}</span>
</a>
</li>
{% endif %}
{% endfor %}
<!--下一页设置-->
<!--判断是否有下一页,有的话可以点击右箭头跳下一页-->
{% if current_books.has_next %}
<li>
<a href="{% url 'show' %}?page={{ current_books.next_page_number }}"
aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<!--没有上一页,让按钮变为disable,不让点击-->
{% else %}
<li class="disabled">
<a aria-label="Next"> <!--注意最后一页没有下一页,所以这里a标签的href属性不能再写了,如果写了,那么current_books.next_page_number方法会一直报错。-->
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
<script src="{% static 'jquery-3.4.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</body>
</html>
django的内置分页器可以实现简单的分页设置,但是如果我们需要涉及到更多细节的设置,更人性化的配置的时候,django内置分页器就无法满足我们的使用需求。
这种场景,我们需要自己定义分页器组件,通过后端传递数据,在分页器组件中,根据分页的业务做逻辑处理,然后拼接成分页器标签返回。拿到分页器标签后,直接render给前端页面,生成在页面中。
这里的自定义分页器,仅仅博主本人写的一个简单的自定义分页器,能够解决常用的分页需求。如果无法满足具体需求,可以根据具体需求进行扩展。
项目下新建utils文件夹,用来存放扩展的功能组件,在utils下新建customPaginator.py,分页器组件代码如下:
import copy
class Paginator:
"""自定义分页器"""
def __init__(self, request, data_counts, per_counts=10, show_counts=5):
"""
初始属性
:param request: 请求的所有请求数据
:param data_counts: 展示的总数据数量
:param per_counts: 每页展示的数据数量
:param show_counts: 在前端显示的页码数量
"""
self.request = request
self.data_counts = data_counts
self.per_counts = per_counts
self.show_counts = show_counts
self.params = copy.deepcopy(request.GET) # 获取请求的GET数据的深拷贝querydict可以使用
# 获取数据分页后总页数
def page_counts():
"""
获取总的页码数量
:return:
"""
page_counts, mod = divmod(self.data_counts, self.per_counts)
if mod:
page_counts += 1
return page_counts
# 获取总页数,并添加在self属性中
self.page_counts = page_counts()
# 获取当前页页码
self.current_page = request.GET.get("page", "")
try: # 异常处理当前页码是否为数字
self.current_page = int(self.current_page)
except Exception:
self.current_page = 1
# 判断当前页码在不在合理范围内
if self.current_page < 1:
self.current_page = 1
if self.current_page > self.page_counts:
self.current_page = 1
@property # 装饰为普通属性
def start(self):
"""
返回某一页数据展示的开始位置
:return:
"""
return (self.current_page - 1) * self.per_counts
@property # 装饰为普通属性
def end(self):
"""
返回某一页数据展示的结束位置
:return:
"""
return (self.current_page) * self.per_counts
def paginate(self):
"""
根据数据数据量,每页数据,每页页码,拼接分页标签返回
:return:返回拼接好的分页器标签
"""
tag = ""
page_counts = self.page_counts
# 设置首页标签url
self.params["page"] = 1
params = self.params.urlencode() # condition=name&q=qwerqw&page=1
if self.current_page == 1:
first = f"""
"""
else:
first = f"""
"""
# 设置上一页标签的url
if self.current_page <= 1:
# 如果当前页是第一页,上一页不可选
previous = """
"""
else:
# 不是第一页,拼接上一页的url路径
self.params["page"] = self.current_page - 1
params = self.params.urlencode() # condition=name&q=qwerqw&page=num
previous = f"""
"""
# 获取要显示的页码范围
half_num = self.show_counts // 2
if self.page_counts < self.show_counts:
# 判断总页数是不是小于要显示的页数
range_start = 1
range_end = self.page_counts
else:
# 总页数大于要显示的页数
if self.current_page <= half_num + 1:
range_start = 1
range_end = self.show_counts
elif half_num + 1 < self.current_page < page_counts - half_num:
range_start = self.current_page - half_num
range_end = self.current_page + half_num
else:
range_start = page_counts - self.show_counts + 1
range_end = page_counts
# 获取中间的页码标签
middle = ""
for num in range(range_start, range_end + 1):
# 保留查询参数的路径
self.params["page"] = num
params = self.params.urlencode() # condition=name&q=qwerqw&page=num
# 判断哪一页是当前页,是的话,添加active效果
if self.current_page == num:
one_tag = f"""{num} """
else:
one_tag = f"""{num} """
middle += one_tag
# 设置下一页标签的url
if self.current_page >= self.page_counts:
# 如果当前页已经是最大页数,下一页禁用
next = """
"""
else:
# 如果不是正常使用
self.params["page"] = self.current_page + 1
params = self.params.urlencode() # condition=name&q=qwerqw&page=num
next = f"""
"""
# 设置尾页标签url
self.params["page"] = self.page_counts
params = self.params.urlencode() # condition=name&q=qwerqw&page=1
if self.current_page == self.page_counts:
last = f"""
"""
else:
last = f"""
"""
tag = f"""
"""
return tag
def jump_page(self):
"""
产生跳转页标签
:return: 返回跳转页的标签
"""
url = self.request.get_full_path()
if not "/?" in url:
url = url+"?page="
else:
if "page" in url:
url = url.split("page")[0]+"page="
else:
url = url + "&page="
jump_tag =f"""
"""
return jump_tag
def jump_js(self):
"""
生成跳转页使用的js代码
:return:
"""
jump_js = """
"""
return jump_js
分页器接受参数
分页器方法
from crmweb import models
from django import views
from utils.customPaginator import Paginator # 导入自定义分页器类
# 展示客户数据的视图
class CommonData(views.View):
@method_decorator(login_required) # 验证客户登录状态的装饰器,这里可有可无
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res
def get(self, request):
# 查询要显示的所有数据
all_customers = models.Customer.objects.filter(consultant__isnull=True, status="unregistered").order_by("-pk")
# 开始分页展示
data_counts = all_customers.count() # 获取分页的总数据数量
# 生成一个分页对象
paginator = Paginator(request, data_counts, 10)
# 获取当前页展示数据的范围
try: # 异常是否查到了数据,查到了才切片,不然会报错
all_customers = all_customers[paginator.start:paginator.end]
except Exception:
pass
# 获取分页的标签
paginator_tag = paginator.paginate() # 调用定义好的分页方法
# 获取跳转页的标签
jump_tag = paginator.jump_page() # 调用定义好的跳转页方法获取跳转页标签
jump_js = paginator.jump_js() # 调用定义好的跳转页方法获取跳转页js代码
return render(request, "customers_common_list.html",
{"all_customers": all_customers, "paginator_tag": paginator_tag,
"jump_tag": jump_tag, "jump_js": jump_js})
<table id="example2" class="table table-bordered table-hover text-center">
<thead>
<tr>
<th style="width: 5%">序号</th>
<th>qq</th>
<th>姓名</th>
<th>电话</th>
<th>来源</th>
<th>咨询课程</th>
<th>客户状态</th>
<th>销售老师</th>
<th>跟进信息</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ customer.qq }}</td>
<td>{{ customer.qq_name }}</td>
<td>
{{ customer.phone|default:"暂无" }}
</td>
<td>{{ customer.get_source_display|default:'暂无' }}</td>
<td>{{ customer.get_course_display|default:"暂无" }}</td>
<td>{{ customer.get_status_display }}</td>
<td>{{ customer.consultant.username|default:'暂无' }}</td>
<td><a href="{% url 'consult_record' customer.pk %}">详情</a></td>
<td>
<a style="color: #00c3cc;" href="{% url 'consult_record_edit' customer.pk %}">
<i class="fa fa-edit" aria-hidden="true"></i>
</a>
|
<a style="color: #d9534f;" href="{% url 'consult_record_del' customer.pk %}">
<i class="fa fa-trash-o"></i>
</a>
</td>
</tr>
</tbody>
</table>
<!--自定义分页器使用-->
<div class="pull-right" style="display:inline-block; width: 120px;margin: 22px 10px">
{{ jump_tag|safe }}
</div>
<!--自定义跳转页使用-->
<div class="pull-right">
{{ paginator_tag|safe }}
</div>
{{ jump_js|safe }}