Django原生sql也能使用Paginator分页的示例代码


Posted in Python onNovember 15, 2017

django-pagination这是一个python包,来自github上的一个项目,很容易用。

不过这是一个懒人工具,好吧(工具理性)。不过当一个页面有多处需要采用分页的话,就行不通了,要么修改django-pagination的源码,改变它的url指向,不过我没研究,当工程涉及到迁移时,要知道要安装各种东西本来就是个缺点,还要再修改源码,那就得不偿失。因而转战django自带的分页插件——Paginator。

Paginator其实只需要实现两个方法`count`和`__getslice__`就可以自定义一个让Paginator支持的对象

0x00 Django分页局限

使用Django肯定经常使用Paginator分页,很便捷。但是他可接受的分页对象必须是django orm的查询集或者list、tuple。

当需要使用原生sql查询数据且分页就无法使用Paginator。

0x01 分页原理

其实分页就是传入数据集、每页数量、当前页数,然后计算(查询)数据总数量,根据每页数量计算出总页数,当前页的开始index和结束index,然后根据开始index和结束index获取本页数据返回。

请注意上面一句话的黑体字部分,它们就是计算分页的核心,那么Paginator其实只需要实现两个方法count和__getslice__就可以自定义一个让Paginator支持的对象,然后就可以使用Paginator分页了,不需要单独对原生sql写分页逻辑

0x02 自定义分页

# coding=utf-8

from django.core.paginator import Paginator


def paginator(data_list, per_page, page_no):
  """封装Django分页"""
  pages = Paginator(data_list, per_page)

  # 防止超出页数
  if not page_no > 0:
    page_no = 1
  if page_no > pages.num_pages:
    page_no = pages.num_pages

  p = pages.page(page_no) # 获取本页数据

  data = dict() # 获取分页信息
  data['count'] = pages.count
  data['page_num'] = pages.num_pages
  data['per_page'] = per_page
  data['current'] = page_no
  data['start_index'] = p.start_index() - 1

  return p.object_list, page_no, data


class QueryWrapper(object):
  """查询集包装器。实现django Paginator需要的必要方法,实现和query一样使用Paginator分页"""

  def __init__(self, sql, params=None, db="default"):
    """
    :param sql: sql语句
    :param params: sql语句的params参数
    :param db: 数据库名称(Django配置)
    """
    self.db = db
    self.sql = sql
    self.params = params

  def count(self):
    """计算总页数"""
    sql = """select count(*) from (%s) _count""" % self.sql
    # sql封装方法请参考https://my.oschina.net/watcher/blog/1573503
    return fetchone_sql((sql, self.params), db=self.db, flat=True) # 返回总页数

  def __getslice__(self, x, y):
    """ self.__getslice(x, y) = self[x:y]"""
    sql = self.sql + ' LIMIT {start}, {num}'.format(start=x, num=y - x)
    # sql封装方法请参考https://my.oschina.net/watcher/blog/1573503
    return fetchall_to_dict((sql, self.params), db=self.db) # 字典列表形式返回


def demo_orm():
  """使用Django的ORM分页"""
  # 示例:查询status=1的用户分页,每页10条,取第2页数据(假设数据量足够)
  status = 1
  per_page = 10
  page_no = 2

  # 使用Django的ORM
  from django.contrib.auth.models import User

  query = User.objects.filter(status=status).values("id", "username", "first_name")
  one_page_data_list, page_no, page_data = paginator(query, per_page, page_no)
  # one_page_data_list 即为第二页数据,例如:[{"id": 1, "username": "111", "first_name": "aaa"}]
  print one_page_data_list


def demo_raw():
  """使用原生sql实现相同分页"""
  # 示例:查询status=1的用户分页,每页10条,取第2页数据(假设数据量足够)
  status = 1
  per_page = 10
  page_no = 2

  sql = "select id, username, first_name from auth_user where status=%(status)s"
  params = {"status": status} # 使用params防止sql注入
  query = QueryWrapper(sql, params, "default")
  one_page_data_list, page_no, page_data = paginator(query, per_page, page_no)
  # one_page_data_list 同ORM获取数据一样
  print one_page_data_list


if __name__ == "__main__":
  demo_orm()
  demo_raw()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python制作Windows系统服务
Mar 25 Python
Python实现压缩文件夹与解压缩zip文件的方法
Sep 01 Python
在Python中实现shuffle给列表洗牌
Nov 08 Python
Python一行代码实现快速排序的方法
Apr 30 Python
Python字符串的修改方法实例
Dec 19 Python
如何在mac环境中用python处理protobuf
Dec 25 Python
VSCode基础使用与VSCode调试python程序入门的图文教程
Mar 30 Python
python 轮询执行某函数的2种方式
May 03 Python
Python限制内存和CPU使用量的方法(Unix系统适用)
Aug 04 Python
python使用matplotlib:subplot绘制多个子图的示例
Sep 24 Python
Python使用eval函数执行动态标表达式过程详解
Oct 17 Python
python 自动化偷懒的四个实用操作
Apr 11 Python
使用Python的turtle模块画图的方法
Nov 15 #Python
python绘制铅球的运行轨迹代码分享
Nov 14 #Python
Python实现句子翻译功能
Nov 14 #Python
简述:我为什么选择Python而不是Matlab和R语言
Nov 14 #Python
Python与R语言的简要对比
Nov 14 #Python
Python基础语言学习笔记总结(精华)
Nov 14 #Python
Python利用multiprocessing实现最简单的分布式作业调度系统实例
Nov 14 #Python
You might like
PHP fastcgi模式上传大文件(大约有300多K)报错
2014/09/28 PHP
ThinkPHP5.1+Ajax实现的无刷新分页功能示例
2020/02/10 PHP
XHTML-Strict 内允许出现的标签
2006/12/11 Javascript
Javascript和Ajax中文乱码吐血版解决方案
2009/12/21 Javascript
复制Input内容的js代码_支持所有浏览器,修正了Firefox3.5以上的问题
2010/06/21 Javascript
使用js如何实现全选与全不选
2013/12/30 Javascript
实现checkbox全选、反选、取消JavaScript小脚本异常
2014/04/10 Javascript
Vuejs第十一篇组件之slot内容分发实例详解
2016/09/09 Javascript
详谈js中window.location.search的用法和作用
2017/02/13 Javascript
JS实现电商放大镜效果
2017/08/24 Javascript
JS删除数组里的某个元素方法
2018/02/03 Javascript
详解Vue.js和layui日期控件冲突问题解决办法
2019/07/25 Javascript
[58:57]2018DOTA2亚洲邀请赛3月29日小组赛B组 Effect VS VGJ.T
2018/03/30 DOTA
[00:49]完美世界DOTA2联赛10月28日开团时刻:随便打
2020/10/29 DOTA
python中关于日期时间处理的问答集锦
2013/03/08 Python
python3访问sina首页中文的处理方法
2014/02/24 Python
Python使用cx_Oracle模块将oracle中数据导出到csv文件的方法
2015/05/16 Python
python 实现A*算法的示例代码
2018/08/13 Python
浅谈django orm 优化
2018/08/18 Python
Python从ZabbixAPI获取信息及实现Zabbix-API 监控的方法
2018/09/17 Python
Python中反射和描述器总结
2018/09/23 Python
Python读取xlsx文件的实现方法
2019/07/04 Python
关于torch.optim的灵活使用详解(包括重写SGD,加上L1正则)
2020/02/20 Python
生物有机护肤品:Aurelia Probiotic Skincare
2018/01/31 全球购物
澳大利亚婴儿喂养品牌:Cherub Baby
2018/11/01 全球购物
几道Java和数据库的面试题
2013/05/30 面试题
简短的公司员工自我评价分享
2013/11/13 职场文书
学校采购员岗位职责
2014/01/02 职场文书
委托协议书范本
2014/04/22 职场文书
安阳殷墟导游词
2015/02/10 职场文书
会计求职自荐信
2015/03/26 职场文书
会议通知
2015/04/15 职场文书
解析Java中的static关键字
2021/06/14 Java/Android
python opencv将多个图放在一个窗口的实例详解
2022/02/28 Python
python标准库ElementTree处理xml
2022/05/20 Python
MySQL使用IF语句及用case语句对条件并结果进行判断 
2022/09/23 MySQL