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 两个列表的差集、并集和交集实现代码
Sep 21 Python
Python通过future处理并发问题
Oct 17 Python
python编写朴素贝叶斯用于文本分类
Dec 21 Python
python使用xpath中遇到:到底是什么?
Jan 04 Python
使用Python读取大文件的方法
Feb 11 Python
Python列表切片操作实例总结
Feb 19 Python
Python学习笔记之图片人脸检测识别实例教程
Mar 06 Python
利用Python实现kNN算法的代码
Aug 16 Python
python getpass模块用法及实例详解
Oct 07 Python
python下载库的步骤方法
Oct 12 Python
Pycharm中Python环境配置常见问题解析
Jan 16 Python
Python爬虫实例——爬取美团美食数据
Jul 15 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作为网站开发语言的原因分享
2012/01/03 PHP
PHP实现的购物车类实例
2015/06/17 PHP
Jquery中获取iframe的代码
2011/01/11 Javascript
Javascript脚本实现静态网页加密实例代码
2013/11/05 Javascript
JavaScript函数详解
2015/02/27 Javascript
JS如何实现文本框随文本的长度而增长
2015/07/30 Javascript
AngularJs实现ng1.3+表单验证
2015/12/10 Javascript
关于获取DIV内部内容报错的原因分析及解决办法
2016/01/29 Javascript
详解如何让InstantClick兼容MathJax、百度统计等
2017/09/12 Javascript
JavaScript实现快速排序的方法分析
2018/01/10 Javascript
使用vue-route 的 beforeEach 实现导航守卫(路由跳转前验证登录)功能
2018/03/22 Javascript
vue.js通过路由实现经典的三栏布局实例代码
2018/07/08 Javascript
webstorm+vue初始化项目的方法
2018/10/18 Javascript
vue-router懒加载速度缓慢问题及解决方法
2018/11/25 Javascript
关于AOP在JS中的实现与应用详解
2019/05/06 Javascript
常见的浏览器存储方式(cookie、localStorage、sessionStorage)
2019/05/07 Javascript
Vue  webpack 项目自动打包压缩成zip文件的方法
2019/07/24 Javascript
何时/使用 Vue3 render 函数的教程详解
2020/07/25 Javascript
[01:02:17]2014 DOTA2华西杯精英邀请赛 5 24 DK VS VG
2014/05/26 DOTA
python logging类库使用例子
2014/11/22 Python
讲解Python中fileno()方法的使用
2015/05/24 Python
Python栈类实例分析
2015/06/15 Python
Python中关键字nonlocal和global的声明与解析
2017/03/12 Python
python连接数据库的方法
2017/10/19 Python
python smtplib模块自动收发邮件功能(一)
2018/05/22 Python
解决python打不开文件(文件不存在)的问题
2019/02/18 Python
Python集中化管理平台Ansible介绍与YAML简介
2019/06/12 Python
django 邮件发送模块smtp使用详解
2019/07/22 Python
python中导入 train_test_split提示错误的解决
2020/06/19 Python
Python爬虫之Selenium设置元素等待的方法
2020/12/04 Python
Java中的类包括什么内容?设计时要注意哪些方面
2012/05/23 面试题
名企HR怎样看待求职信
2014/02/23 职场文书
2014年技术部工作总结
2014/12/12 职场文书
班主任经验交流心得体会
2015/11/02 职场文书
2016保送生自荐信范文
2016/01/29 职场文书
vue二维数组循环嵌套方式 循环数组、循环嵌套数组
2022/04/24 Vue.js