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爬取网站数据保存使用的方法
Nov 20 Python
Python多进程池 multiprocessing Pool用法示例
Sep 07 Python
在Python中分别打印列表中的每一个元素方法
Nov 07 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
Mar 01 Python
Python之lambda匿名函数及map和filter的用法
Mar 05 Python
Python基础之循环语句用法示例【for、while循环】
Mar 23 Python
python中property和setter装饰器用法
Dec 19 Python
Python *args和**kwargs用法实例解析
Mar 02 Python
python模拟实现分发扑克牌
Apr 22 Python
Pytorch数据拼接与拆分操作实现图解
Apr 30 Python
Python 实现微信自动回复的方法
Sep 11 Python
Python全局变量与global关键字常见错误解决方案
Oct 05 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
NOT NULL 和NULL
2007/01/15 PHP
php iconv() : Detected an illegal character in input string
2010/12/05 PHP
如何判断php数组的维度
2013/06/10 PHP
php比较相似字符串的方法
2015/06/05 PHP
JS的replace方法介绍
2012/10/20 Javascript
js/jquery解析json和数组格式的方法详解
2014/01/09 Javascript
如何正确使用javascript 来进行我们的程序开发
2014/06/23 Javascript
60行js代码实现俄罗斯方块
2015/03/31 Javascript
JavaScript 函数的执行过程
2016/05/09 Javascript
jQuery弹出层后禁用底部滚动条(移动端关闭回到原位置)
2016/08/29 Javascript
ES6学习之变量的解构赋值
2017/02/12 Javascript
JavaScript正则替换HTML标签功能示例
2017/03/02 Javascript
微信小程序-横向滑动scroll-view隐藏滚动条
2017/04/20 Javascript
Angular2.0/4.0 使用Echarts图表的示例代码
2017/12/07 Javascript
jquery实现侧边栏左右伸缩效果的示例
2017/12/19 jQuery
vue+element-ui+ajax实现一个表格的实例
2018/03/09 Javascript
利用vue.js把静态json绑定bootstrap的table方法
2018/08/28 Javascript
Angular5中状态管理的实现
2018/09/03 Javascript
React生命周期原理与用法踩坑笔记
2020/04/28 Javascript
JavaScript编码小技巧分享
2020/09/17 Javascript
python动态加载变量示例分享
2014/02/17 Python
Python数据结构与算法之字典树实现方法示例
2017/12/13 Python
Python实现的用户登录系统功能示例
2018/02/05 Python
基于Python实现用户管理系统
2019/02/26 Python
华为校园招聘上机笔试题 扑克牌大小(python)
2020/04/22 Python
python实现串口自动触发工作的示例
2019/07/02 Python
Django urls.py重构及参数传递详解
2019/07/23 Python
Python for i in range ()用法详解
2020/09/18 Python
英国家电直销:Appliances Direct
2016/09/22 全球购物
英国Lookfantastic中文网站:护肤品美妆美发购物(英国直邮)
2020/04/27 全球购物
最新结婚典礼主持词
2014/03/14 职场文书
村创先争优活动总结
2014/08/28 职场文书
导游欢送词
2015/01/31 职场文书
毕业论文致谢部分怎么写
2015/05/14 职场文书
《秦兵马俑》教学反思
2016/02/24 职场文书
基于Redis zSet实现滑动窗口对短信进行防刷限流的问题
2022/02/12 Redis