文档章节

Django原生sql也能使用Paginator分页

张豪飞
 张豪飞
发布于 2017/11/14 17:28
字数 689
阅读 130
收藏 5

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()

© 著作权归作者所有

共有 人打赏支持
张豪飞
粉丝 27
博文 39
码字总数 19714
作品 0
郑州
程序员
私信 提问
Django+boostrap分页(1)

源起 我想要优雅地使用+ 来实现分页,忽然发现不知道该如何做起我照葫芦画瓢知道了怎么使用列表组件,也大概知道怎么使用,但是放到一起我就彻底懵逼了。 资料收集 基本分页演示 如果想使用禁...

mhye
2016/10/09
80
0
django paginator基本使用方法

分页是Web应用常用的手法,Django提供了一个分页器类Paginator(django.core.paginator.Paginator),可以很容易的实现分页的功能。该类有两个构造参数,一个是数据的集合,另一个是每页放多少...

jacked
2015/11/13
0
0
Django-----分页

一、目的 因为往往数据库中的数据在前端页面展示出来一页肯定是不够的,而一个网页的容量就那么大,所以肯定要分页显示。 二、实施 其实仔细想想,如果数据量小的话,直接在后台的views处理函...

AltBoy
2017/06/26
0
0
Django Paginator属性及方法

Django分页的基本操作在Django文档有简单的例子,基本上看一下就知道。核心代码在django.core.paginator.py中。 分页对象Paginator: 只需提供两个必要的参数,第一个就是用于展示的数据(o...

北方攻城师
2015/06/17
0
0
如何用Django分页器实现文章分页?

1、概述 Django有自带的分页器,可以将数据分在不同的页面中,并提供一些属性和方法实现对分页数据的操作。分页功能的类位于django/core/paginator.py中。 2、数据准备 在具体实现分类器功能...

mcyJacky的博客
2017/12/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用Autowired和Qualifier解决多个相同类型的bean如何共存的问题

注意: 实现类UserServiceImpl,MyUserServiceImpl 需要区分:@Service("userServicel") @Service("myUserService") https://blog.csdn.net/russle/article/details/80287763......

qimh
16分钟前
1
0
SQL 语句使用to_char函数时,检索结果有空格

小疯在使用Oracle过程中,使用to_char函数检索表数据时发现检索结果前面会有一个空格,对后续开发有影响。问题很好解决,比较直接对可以做一下trim处理。但是小疯很疑惑为什么会有空格呢,于...

野小疯
17分钟前
1
0
对接比特币钱包的PHP开发包

BtcTool是一个基于第三方服务和离线裸交易实现的PHP比特币应用开发包,适合不希望部署本地 节点旳PHP开发者,开发包主要包含以下特性: 利用第三方服务获取指定地址的utxo集合 离线生成消费裸...

汇智网教程
35分钟前
1
0
【自用】 VHD to VHDX

VHDX: 在VHD 2TB 的基础上提供 64TB的容量。 支持逻辑扇区大小为 4KB,和每块的大小为 256MB,来优化虚拟磁盘性能。 比VHD提供更高的安全性、可靠性和性能。 convert-VHD –path d:\Hyper-v...

Tensor丨思悟
48分钟前
3
0
30 岁转行做Python开发晚吗?而且是零基础

最近有小伙伴问小编,30 岁转行做Python开发晚吗? 小编想说,其实无论男女,只要想学,有这个动力,就直接去行动。无论年龄,无论性别,只要你想一直勇往直前,那么想做的就去做吧~这里有一...

糖宝lsh
58分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部