- 1. 批量操作数据
- bulk_create 方法
- 2. 分页器推导
- 分页器最终版本
在操作大批数据的时候,例如在数据库表中插入大批量的记录时,可以使用该方法减少运行时间,首先可以尝试直接插入多条数据,如下所示
urls.py
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^get_book/',views.get_book) ]
models.py
from django.db import models class Book(models.Model): title = models.CharField(max_length=64)
views.py
from django.shortcuts import render, HttpResponse, redirect from app01 import models def get_book(request): # for循环插入1000条数据 for i in range(1000): models.Book.objects.create(name='第%s本书'%i) # 将插入的数据再查询出来 book_queryset = models.Book.objcets.all() return render(request,'get_book.html',locals()) # 将查询出来的数据传递给html页面
template/get_book.html
Title
{% load static %}
{#对结果集进行for循环#}
{% for book in book_queryset %}
{#循环展示书名#}
{{ book.title }}
{% endfor %}
在插入大批量的时候,浏览器会等待很久,这是因为后端在不停的操作数据库,所以看起来想卡了,直接操作大批量的数据效率并不高,我们可以使用 bulk_create方法提升效率
bulk_create 方法在 views.py 中使用该方法即可
from django.shortcuts import render, HttpResponse, redirect
from app01 import models
def get_book(request):
'''批量插入'''
book_list = []
for i in range(100000):
# 先用类产生一个对象
source_book_obj = models.Books(title=f'第{i}本书')
# 将对象追加到列表中
book_list.append(source_book_obj)
models.Books.objects.bulk_create(book_list) # 批量插入
book_queryset = models.Books.objects.all()
return render(request,'many_data.html',locals())
2. 分页器推导
在前面批量插入了多条数据,但是肯定不能在页面上同时展示这么多数据,就需要使用分页器的功能了。
1. 首先分页,首先肯定要有展示数据的条数、开始展示的位置、结束展示的位置、分页器页码的数量等参数。
2. 我们可以在路由后携带类似于 https://blog.csdn.net/m0_58987515/article/details/124890894?page=1 的数据来表示当前页码,并对结果集进行切片让其展示固定位置数据。
class sorter(View):
def get(self, request):
# 获取请求中的page值
page_num = request.GET.get('page')
try:
# 将其转为数字类型
page_num = int(page_num)
except Exception:
# 如果不存在将其转为1
page_num = 1
# 对结果集进行切片操作
book_queryset = models.Books.objects.all()[20:30]
3. 虽然可以展示出指定位置的数字,但是此时是写死的,我们需要动态的获得指定的位置,在此我们可以看下页码参数 (page_num)、开始的位置(start_num)和结束的位置(stop_num)以及展示的条数(show_num)之间的关系,如下表所示
| 页码展示条数 | 页码 | 结果集开始位置 | 结果集结束位置 |
|---|---|---|---|
| 5 | 1 | 0 | 5 |
| 5 | 2 | 5 | 10 |
| 5 | 3 | 10 | 15 |
| 页码展示条数 | 页码 | 结果集开始位置 | 结果集结束位置 |
|---|---|---|---|
| 10 | 1 | 0 | 10 |
| 10 | 2 | 10 | 20 |
| 10 | 3 | 20 | 30 |
4. 我们可以发现,结果集开始的位置是页码展示条数与页码减一的乘积,而结果集结束的位置是页码展示条数和页码的乘积
关系如下所示,此时就可以动态的切片结果集了,如下所示
# 关系展示
start_num = show_num * (page_num - 1)
stop_num = show_num * page_num
# 动态切割结果集
class sorter(View):
def get(self, request):
page_num = request.GET.get('page')
try:
page_num = int(page_num)
except Exception:
page_num = 1
# 设置最大展示的条数
show_num = 10
# 动态结果集起始的位置
start_num = (page_num-1) * show_num
# 动态结果集结束的位置
stop_num = page_num * show_num
# 对结果集动态切片
book_queryset = models.Books.objects.all()[start_num:stop_num]
return render(request, 'book.html', locals())
5. 接下来就是引入分页器的样式了,这里使用的是 Bootstrap 框架提供的分页器,修改其链接,如下{% for foo in book_queryset %}{{ foo.name }}
{% endfor %}
6. 虽然实现了简易分页,但是其跳转的页码是写死的,我们可以把它放在后端编写,首先要了解页码数量和数据条数之间的 关系,如下表所示,就算数据条数只多出一条,也要一个页码储存。在后端使用的方法是 'divmod', divmod() 函数把除 数和余数运算结果结合起来,返回一个包含商和余数的元组,如下示意 # divmod 内置方法使用示意 >>> divmod(100,10) (10, 0) # 10页 >>> divmod(101,10) (10, 1) # 11页 >>> divmod(99,10) (9, 9) # 10页 # 余数只要不是0就需要在第一个数字上加一
| 数据条数 | 页码最大展示条数 | 页码数 |
|---|---|---|
| 99 | 10 | 10 |
| 100 | 10 | 10 |
| 101 | 10 | 11 |
7. 在后端编写html代码发生到前端,如下所示
'views.py文件'
class sorter(View):
def get(self, request):
page_num = request.GET.get('page')
# 获取当前结果集
data_queryset = models.Books.objects.all()
try:
page_num = int(page_num)
except Exception:
page_num = 1
show_num = 10
start_num = (page_num - 1) * show_num
stop_num = page_num * show_num
# 获取结果集数据的个数
all_count = data_queryset.count()
# 使用divmod方法
more, others = divmod(all_count, page_num)
# 如果有余数,页码数量加1
if others:
more += 1
# 创建空字符串用于接收html代码
html = ''
# for循环,循环生成html代码
for i in range(1, more+1):
# 添加到空字符串中
html += f'
{% for foo in book_queryset %}
{{ foo.name }}
{% endfor %}8. 页码已经有了功能,但是现在是一次性将页码都展示,我们需要对其最终优化,如下
class sorter(View):
def get(self, request):
# 获取当前页码page值
page_num = request.GET.get('page')
# 获取结果集
data_queryset = models.Books.objects.all()
try:
# 将其转为数字类型
page_num = int(page_num)
except Exception:
# 异常时赋值为1
page_num = 1
# 定义一个页码展示的最大条数
show_num = 10
# 动态获取结果集切片开始的位置
start_num = (page_num - 1) * show_num
# 动态获取结果集切片结束的位置
stop_num = page_num * show_num
# 获取结果集数据的总条数
all_count = data_queryset.count()
# 获取整除数和余数,整除的数量就是页码的总数量,余数是多出来的数据条数
more, others = divmod(all_count, show_num)
if others:
# 如果有余数,需要在添加一页存放数据
more += 1
# 创建一个变量指向当前页码
more_page = page_num
# 若当前页码小于等于6,range(1, 12)。
if more_page < 6:
more_page = 6
# 假设最大页码数是27,若当前页码大于22时,例如为23,则range(17,28)。页码为25也为range(17,28)
if more_page > (more - 5):
more_page = more - 5
# 创建空字符串
html = ''
# 这里设定只展示11个页码,不小于6和不大于more - 5的页码按照其所在位置展示前后5个页码
for i in range(more_page - 5, more_page + 6):
# 将当前页码添加高亮
if i == page_num:
html += f'class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
''')
return ''.join(page_html_list)
最终版本使用
由于分页器会多次使用,我们可以创建一个utils文件夹用于存放分页器,将上面的类放到utils文件夹下的py文件中
后端
def get_book(request):
# 产生结果集对象
book_queryset = models.Book.objects.all()
# 获取page值
current_page = request.GET.get("page",1)
# 统计结果集个数
all_count = book_queryset.count()
# 实例化类,其中 page值、结果集个数是必传的参数,其他参数有设置默认值
page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
# 动态切片结果集
page_queryset = book_queryset[page_obj.start:page_obj.end]
return render(request,'book.html',locals())
前端
{% for book in page_queryset %}{{ book.title }}
{% endfor %} {{ page_obj.page_html|safe }}



