分页的原理
Django是一个非常全面的Web框架,也预置了分页的功能,这点稍后介绍。然而,我并不想按照Django给的分页功能来做。学习一个东西最好学习它的本质。分页的原理其实很简单,就是根据你传入的参数从数据库获取一部分的数据来展示。比如按照5篇文章来分页,每次就从数据库取5条数据,然后返回给前端展示即可。
手动分页
models的配置,并且一经使用了makemigrations和migrate同步了数据库中的表
class Host(models.Model): name = models.CharField(max_length=10) ip = models.GenericIPAddressField() def __str__(self): return self.name
view的设置
def batch(request, page): page = transfer2int(page, 1) count = Host.objects.count() per_item = transfer2int(request.COOKIES.get("pageNum", 30), 30) print("每页的大小", per_item) # 总页数 page_num = math.ceil(count/per_item) if page > page_num: page = page_num elif page <= 0: page = 1 # 本页的开始 start = (page - 1) * per_item end = min(page * per_item, count) hosts = Host.objects.all()[start:end] print("page", page) print(hosts) if page_num <= 11: startIndex = 1 endIndex = page_num else: if page <6: startIndex = 1 endIndex = 11 elif page + 5 > page_num: endIndex = page_num startIndex = page_num - 10 else: startIndex = page - 5 endIndex = page + 5 return render(request, "batch.html", {"hosts": hosts, "count": count, "bars": range(startIndex, endIndex+1), "page_num": page_num, "page": page}
page是从url出接收到的页码,也就是第几页,函数transfer2int是为了将字符串page转成数值型
def transfer2int(arg, default): try: result = int(arg) except ValueError as e: result = default return result
count是表中的总记录数
per_item是每页有多少条记录
page_num是总页数
hosts 是查询好的数据记录信息
为了页面显示友好,也可以展示 页码条,当前是总共展示11个选择
页面配置信息
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>分页</title> <script type="text/javascript" src="{% static 'js/jquery-3.1.1.js' %}"></script> <script type="text/javascript" src="{% static 'js/jquery.cookie.js' %}"></script> <style type="text/css"> table, td{ border: solid 1px blueviolet; } #paging a{ background-color: green; border: white solid 1px; text-decoration: none; color: white; } #paging a.selected{ color: red; } </style> </head> <body> <table> <tr> <td>主机名</td> <td>IP</td> </tr> {% for host in hosts %} <tr> <td>{{ host.name }}</td> <td>{{ host.ip }}</td> </tr> {% endfor %} </table> <div>总条数{{ count }}</div> <select id="pageNum" onchange="changePageNum();"> <option value="10">10</option> <option value="20">20</option> <option value="30">30</option> <option value="50">50</option> <option value="100">100</option> </select> <div id="paging"> {% if page_num == 1 %} <a href="/shop/batch/1/">1</a> {% else %} {% if page > 1 %} <a href="/shop/batch/1/">首页</a> {% endif %} {% if page >= 2 %} <a href="/shop/batch/{{ page|add:-1 }}/">上一页</a> {% endif %} {% for bar in bars %} {% if page == bar %} <a href="/shop/batch/{{ bar }}/" class="selected">{{ bar }}</a> {% else %} <a href="/shop/batch/{{ bar }}/">{{ bar }}</a> {% endif %} {% endfor %} {% if page < page_num %} <a href="/shop/batch/{{ page|add:1 }}/">下一页</a> <a href="/shop/batch/{{ page_num }}/">尾页</a> {% endif %} {% endif %} </div> <script type="text/javascript"> var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); $(function () { var pageNum = $.cookie("pageNum"); if (pageNum>0){ $("#pageNum").val(pageNum); } else { $("#pageNum").val(30); } }); </script> </body> </html>
原来我使用了ajax,在本例中没有使用。ajax在下篇随笔中会说明。
Django分页
django分页的关键使用了
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
关键是view中的编写
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger def batch2(request): page = transfer2int(request.GET.get('page'), 1) count = Host.objects.count() per_item = 10 print("每页的大小", per_item) all_host = Host.objects.all() paginator = Paginator(all_host, per_item) # Show 25 contacts per page try: hosts = paginator.page(page) except PageNotAnInteger: # If page is not an integer, deliver first page. hosts = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. hosts = paginator.page(paginator.num_pages) return render(request, "batch2.html", {"hosts":hosts})
页面如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>django分页</title> </head> <body> {% for host in hosts %} {{ host.name }}<br> {% endfor %} <div class="pagination"> <span class="step-links"> {% if hosts.has_previous %} <a href="?page={{ hosts.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ hosts.number }} of {{ hosts.paginator.num_pages }}. </span> {% if hosts.has_next %} <a href="?page={{ hosts.next_page_number }}">next</a> {% endif %} </span> </div> </body> </html>
还有一个问题没有解决哦,因为肯定有朋友会问,如果一个列表有100000个item, 我们想要实现每页40个,那么,当将我们请求该列表时,paginator 在分页过程中,请求数据库是取40个,还是取100000啊!显然,paginator 是不可能取100000的啦。paginator 巧妙的利用了Django延迟获取数据的特性,因此,paginator 每次取数据都是只取每页的数据的(也就是上例中的40个),所以是不会有性能 影响 的哦。
官方文档 https://docs.djangoproject.com/en/1.10/topics/pagination/