闲来无事便写了一个易使用,易移植的Python Web分页组件。使用的技术栈是Python、Django、Bootstrap。

既然是易使用、易移植的组件,首先介绍一下其在django框架中的调用方式吧。我将组件封装成了Django InclusionTag,在template模板中直接调用tag即可,代码如下:

{% load pager_tags %}

{% pager request 100 10 %}

  其中 pager_tags是封装的tag文件名,这个无需多说,不了解django框架custom filter、tag的可在官方文档查看。

pager是注册的tag名,后面是传递到pager的参数。request是django的请求对象,100是最大页数,10是导航页码的个数。

可以看到,整个组件的调用是非常简单的,比起django自带的分页器paginator要轻巧很多,这也是我决定开发这个组件的主要原因之一。当然组件使用的便利性带来的是灵活度的牺牲,其扩展能力十分有限,而且依赖于前端框架Django。所以,想要定制一些特别的功能或者样式的小伙伴还是应该选择paginator自行开发。

接下来我们看看tag是怎么写的吧。

from django import template

from garra_rbac.services import page_service

register = template.Library()

@register.inclusion_tag('garra_pager.html')
def pager(request, max_index, show_count=5):
_page = request.GET.get('page')
page = 1
if _page:
page = int(_page)
param = request.GET.urlencode()
page_obj = page_service.PageObject(page, max_index, param, show_count)
return {'page_obj': page_obj}

  我在tag中并没有做太多的事情,只是处理了当前页面的请求参数。其中当前页默认为0,并把GET的参数传递下去,当点击其他页码时要保留参数条件。

我们再看看garra_pager.html吧,html页面是依赖于Bootstrap开发的,不过对于样式的修改也很容易实现。

{% if page_obj.has_page_item %}
<nav aria-label="Page navigation">
<ul class="pagination">
{% for page_index in page_obj.page_index_list %}
<li {% if page_obj.current_index == page_index.index %}class="active"{% endif %}>
<a href="{{ page_index.url }}"
class="{{ page_obj.current_index }}">{{ page_index.text }}</a>
</li>
{% endfor %}
</ul>
</nav> {% else %}
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
暂无数据
</div>
{% endif %}

  html代码很好理解,都是数据的展示,并添加了暂无数据的提示。

最后我们看看分页组件功能的主要实现部分,page_service的代码。

import math

def get_lhalf(show_count):
"""
获取当前页的左侧最多右多少个页码
:param show_count:展示的页码个数
:return:当前页的左侧最多右多少个页码
"""
if show_count % 2 == 0: # 如果为偶数,则让当前页的左侧页码个数比右侧少1
return show_count / 2 - 1
else: # 如果为奇数,左右侧页码个数相同
return math.floor(show_count / 2) def get_param(param, index):
'''
保留原搜索条件,并更新page当前页条件
:param param:原搜索条件
:param index:当前页
:return:更新当前页后的搜索条件
'''
if param:
param = '?' + param
if '?page' in param or '&page' in param:
import re
param = re.sub(r'page=\d+', 'page=%s' % index, param)
else:
param += '&page=%s' % index
else:
param = "?page=%s" % index
return param class PageObject(object):
def __init__(self, current_index, max_index, param, show_count=5):
'''
分页组件对象
:param current_index:当前页码
:param max_index: 最大页码
:param param: 搜索条件
:param show_count: 展示的页码个数
'''
self.current_index = current_index
self.max_index = max_index
self.show_count = show_count if show_count > 5 else 5
self.page_index_list = list()
self.__set_page_index_list(param) @property
def has_page_item(self):
"""
是否有页码数据
:return:
"""
return self.max_index > 0 def __set_page_index_list(self, param):
'''
设置页码按钮
:param param:原搜索条件
:return:
'''
lhalf = get_lhalf(self.show_count) # 左半边应有的数量 l_temp_index = self.current_index - lhalf # 临时左页码
_roffest = 0 # 右迁移量
if l_temp_index < 1: # 左页码需大于0,否则应向右偏移
_roffest = -l_temp_index + 1
lindex = l_temp_index + _roffest # 左页码 = 临时左页码向左偏移后的值 r_temp_index = lindex + self.show_count - 1 # 临时右页码
_loffest = 0 # 左位移量
if self.max_index - r_temp_index < 0: # 右页码需大于最大页码,否则应向左偏移
_loffest = r_temp_index - self.max_index
lindex = lindex - _loffest # 左页码向左偏移
if lindex < 1: # 左页码偏移后的最小值为1,当max_index<show_count时 多余部分需舍弃
lindex = 1
rindex = r_temp_index - _loffest # 右页码 = 临时右页码向右偏移后的值 # region 添加按钮 # 首页按钮
page_first = PageIndex(1, '首页', param)
page_first.index = -1 # 此处设置是为了避免page=1时首页按钮被标记为选中状态的情况,尾页同理
self.page_index_list.append(page_first) # 上一页按钮,如果当前页是第一页则不显示
if self.current_index > 1:
page_prev = PageIndex(self.current_index - 1, '上一页', param)
self.page_index_list.append(page_prev) # 快速后退跳转按钮
if lindex > lhalf:
page_left_skip = PageIndex(lindex - lhalf, "‧‧‧", param)
self.page_index_list.append(page_left_skip) # 页码按钮
for index in range(lindex, rindex + 1):
page_index = PageIndex(index, str(index), param)
self.page_index_list.append(page_index) # 快速前进跳转按钮
if self.max_index - rindex > lhalf:
page_left_skip = PageIndex(rindex + lhalf, "‧‧‧", param)
self.page_index_list.append(page_left_skip) # 下一页按钮,如果当前页是最后一页则不显示
if self.current_index < self.max_index:
page_next = PageIndex(self.current_index + 1, '下一页', param)
self.page_index_list.append(page_next) # 尾页按钮
page_last = PageIndex(self.max_index, '尾页', param)
page_last.index = -1
self.page_index_list.append(page_last) # endregion class PageIndex(object):
def __init__(self, index, text, param):
self.index = index
self.text = text
self.url = get_param(param, index)

  整个page_service主要分为两个功能,第一是求出组件的最左侧页码和最右侧页码的数值,第二是添加全部按钮给template渲染。

稍微解释一下算法,我首先取到了当前页左侧页码数的最大值,并求出此时最左侧的页码值,如果其小于1 则整个页码组件需要向右侧移动 直至最左侧的页码为1。尔后计算出最右侧的页码,并和最大页码进行比较,如果最右侧页码大于最大页码,则整个页码组件需要向左侧移动。注:由于最左侧页码已经算出,如需左移组件,最左侧页码也应该进行移动,并应注意 最左侧页码不能小于1。

此时我们拿到了分页组件的最左侧页码和最右侧页码,就可以添加按钮并进行渲染了。

如此一来,分页所需要的主要功能就都被我们实现了,而且调用简单,源码简洁,为此我牺牲了扩展性,使其和paginator分页器有一个极为明显的差别,可根据不同场景进行选择。

python web 分页组件的更多相关文章

  1. Python自定义分页组件

    为了防止XSS即跨站脚本攻击,需要加上 safe # 路由 from django.conf.urls import url from django.contrib import admin from ...

  2. 基于 Python 的自定义分页组件

    基于 Python 的自定义分页组件 分页是网页中经常用到的地方,所以将分页功能分出来,作为一个组件可以方便地使用. 分页实际上就是不同的 url ,通过这些 url 获取不同的数据. 业务逻辑简介 ...

  3. Python分页组件

    分页组件的实现: class Pagination(object): """ 自定义分页 """ def __init__(self,cur ...

  4. python三大web框架Django,Flask,Flask,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架

    Python几种主流框架 从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python We ...

  5. Python Web(二)

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.Django-debug-toolbar django-debug-toolbar 是一组可配置的面板,可显示 ...

  6. Django,Flask,Tornado三大框架对比,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架

    Django 与 Tornado 各自的优缺点Django优点: 大和全(重量级框架)自带orm,template,view 需要的功能也可以去找第三方的app注重高效开发全自动化的管理后台(只需要使 ...

  7. 浅谈五大Python Web框架

    转载:http://feilong.me/2011/01/talk-about-Python-web-framework 说到Web Framework,Ruby的世界Rails一统江湖,而Pytho ...

  8. Python Web 开发的十个框架【转载】

    Python 是一门动态.面向对象语言.其最初就是作为一门面向对象语言设计的,并且在后期又加入了一些更高级的特性.除了语言本身的设计目的之外,Python标准 库也是值得大家称赞的,Python甚至还 ...

  9. tornado 学习笔记2 Python web主流框架

    2.1 Django 官方网址:https://www.djangoproject.com/ 简介:Django is a high-level Python Web framework that e ...

随机推荐

  1. Apache Spark 2.2.0 中文文档 - Spark RDD(Resilient Distributed Datasets)

    Spark RDD(Resilient Distributed Datasets)论文 概要 1: 介绍 2: Resilient Distributed Datasets(RDDs) 2.1 RDD ...

  2. mysql DOS中中文乱码 ERROR 1366 (HY000): Incorrect string value: '\xC4\xEA\xBC\xB6' for column 'xxx' at row 1

    问题:ERROR (HY000): Incorrect string value: 在DOS中插入或查询中文出现乱码 登入mysql,输入命令:show variables like '%char%' ...

  3. fuzzy commitment 和fuzzy vault

    Alice,这位令人惊异的魔术天才,正表演关于人类意念的神秘技巧.她将在Bob选牌之前猜中Bob将选的牌!注意Alice在一张纸上写出她的预测.Alice很神秘地将那张纸片装入信封中并封上.就在人们吃 ...

  4. android发编译

    普通的反编译http://blog.csdn.net/vipzjyno1/article/details/21039349/ 反编译os http://gikir.com/blog/?p=115 ht ...

  5. CSIC_716_20191106【列表、元组、字典、集合】

    python的数据类型及其内置方法 一.列表(续) list.count( ).list.index( ) list = ['1', '2', '3', '2', 'a', 'b', 'c', 'a' ...

  6. LUOGU P1402 酒店之王 (网络流)

    解题思路 应该比较显然得能看出这是个网络流,将$S$与房间连边,房间与人连边,人与菜连边,菜与汇点连边,边的流量均为1.但这样是错误的,因为有可能一个人跑过去2的流量,所以要将人拆点限流. #incl ...

  7. [BJOI 2018]染色

    题意:求01成立. 并查集维护,记录一个变量判断决策. #include<bits/stdc++.h> using namespace std; #define int long long ...

  8. Kafka和RabbitMQ 对比

    1)  Kafka成为业界大数据松耦合架构,异步,队列 特点:吞吐量高50m/s. Kafka和RabbitMQ都是MQ机制,它差异 Kafka作为大数据产品,可以作为数据源,也可以作为结果数据中转 ...

  9. MongoDB后台运行

    文章目录 命令方式(推荐) 命令行和配置文件方式 命令行: 配置文件: 命令方式(推荐) 如果想在后台运行,启动时只需添加 --fork函数即可. fork: 以守护进程的方式运行MongoDB. 指 ...

  10. SQL Serve 临时表

    SQL Server 支持临时表.临时表就是那些名称以井号 (#) 开头的表.如果当用户断开连接时没有除去临时表,SQL Server 将自动除去临时表.临时表不存储在当前数据库内,而是存储在系统数据 ...