关键词:python、flask、flask-sqlalchemy、pagination、bootstrap、分页
漫画场景:某个阳光灿烂的早上,程序猿们纷纷来到办公室。幸福的提着爱心便当午餐(小便当叫小便,大便当叫大便),纯屌丝的在路边买一盒炒粉或者是热干面。正享受着早上的阳光,正聊得火热,正吃得挺香……我们的习总匆忙来到办公室,平时不是这么早的,印堂发黑,哦不对,是面色发黑。怒吼一声,开会。
“那个傻X写的分页,数据全部加载到内存去,分页样式可以跟铁道部的网站有得一拼……”
众人沉默,必须沉默。其实其实,分页用table也是为了兼容浏览器,还有我还不会用div啊,必须是table啊。
沉默之后,“重构吧”。
于是经常爱喝咖啡(Java)的程序员发言,让我花一天时间写个Pagination类、分页标签……
坐在旁边拍黄片的程序员,Pagination类,CI框架已经自带了,但实话说,那Pagination类让人抓狂,代码太多了,得简化一下……
大家都把眼光转移到python程序员身上,虽然有点不适,但是还是要说点什么吧。“人生苦短,我用python。我想库已经有这样的Pagination类了,import一下就行了。”
from app.models import Orderpagination = Order.query.paginate(page, per_page = 20)
是的,只要两行代码就行了,当然你的Order实体得是一个orm映射。
有时我们只是想得到一个简单的分页样式而已,那可以使用下面的代码。
from flask.ext.sqlalchemy import Paginationpagination = Pagination(None, page, per_page, order_count, None)
接着我们可以在模板中写一个分页宏,以供全局调用。
{% macro pagination_html(pagination, endpoint, query_string) -%}<div>? <ul>??? <li><a href="http://cjs.linuxapp.org/"javascript:void(0);">??????? 总共{{ pagination.total }}条/{{ pagination.pages }}页</a></li>?????? ???? {% if pagination.has_prev %}??? <li><a href="{{ pagination_href(endpoint, pagination.prev_num, query_string) }}">上一页</a></li>??? {% endif %}??? {% for page in pagination.iter_pages() %}????? {% if page %}??????? {% if page != pagination.page %}????????? <li><a href="{{ pagination_href(endpoint, page, query_string) }}">{{ page }}</a></li>??????? {% else %}????????? <li><a href="javascript:void(0);">{{ page }}</a></li>??????? {% endif %}????? {% else %}??????? <li><a href="javascript:void(0);">…</a></li>????? {% endif %}??? {% endfor %}??? {% if pagination.has_next %}??? <li><a href="{{ pagination_href(endpoint, pagination.next_num, query_string) }}">下一页</a></li>??? {% endif %}? </ul></div>{%- endmacro %}{% macro pagination_href(endpoint, page, query_string) -%}{{ url_for(endpoint, page=page) }}{% if query_string %}{{ '?' + query_string }}{% endif %}{%- endmacro %}
<!-- 调用分页模板 -->{{ pagination_html(pagination, request.endpoint, request.query_string) }}
注意,上面的分页样式依赖于bootstrap的分页样式,如果你想实现自己的样式需要重新改动一下pagination_html宏,而不是完全照抄我的。
最后,我们来读一下这个Pagination类的实现
class Pagination(object): """Internal helper class returned by :meth:`BaseQuery.paginate`. You can also construct it from any other SQLAlchemy query object if you are working with other libraries. Additionally it is possible to pass `None` as query object in which case the :meth:`prev` and :meth:`next` will no longer work. """ def __init__(self, query, page, per_page, total, items): #: the unlimited query object that was used to create this #: pagination object. self.query = query #: the current page number (1 indexed) self.page = page #: the number of items to be displayed on a page. self.per_page = per_page #: the total number of items matching the query self.total = total #: the items for the current page self.items = items @property def pages(self): """The total number of pages""" return int(ceil(self.total / float(self.per_page))) def prev(self, error_out=False): """Returns a :class:`Pagination` object for the previous page.""" assert self.query is not None, 'a query object is required ' \ 'for this method to work' return self.query.paginate(self.page - 1, self.per_page, error_out) @property def prev_num(self): """Number of the previous page.""" return self.page - 1 @property def has_prev(self): """True if a previous page exists""" return self.page > 1 def next(self, error_out=False): """Returns a :class:`Pagination` object for the next page.""" assert self.query is not None, 'a query object is required ' \ 'for this method to work' return self.query.paginate(self.page + 1, self.per_page, error_out) @property def has_next(self): """True if a next page exists.""" return self.page < self.pages @property def next_num(self): """Number of the next page""" return self.page + 1 def iter_pages(self, left_edge=2, left_current=2, right_current=5, right_edge=2): """Iterates over the page numbers in the pagination. The four parameters control the thresholds how many numbers should be produced from the sides. Skipped page numbers are represented as `None`. This is how you could render such a pagination in the templates: .. sourcecode:: html+jinja {% macro render_pagination(pagination, endpoint) %} <div class=pagination> {%- for page in pagination.iter_pages() %} {% if page %} {% if page != pagination.page %} <a href="http://cjs.linuxapp.org/"{{ url_for(endpoint, page=page) }}">{{ page }}</a> {% else %} <strong>{{ page }}</strong> {% endif %} {% else %} <span class=ellipsis>…</span> {% endif %} {%- endfor %} </div> {% endmacro %} """ last = 0 for num in xrange(1, self.pages + 1): if num <= left_edge or \ (num > self.page - left_current - 1 and \ num < self.page + right_current) or \ num > self.pages - right_edge: if last + 1 != num: yield None yield num last = num
原文地址:web分页那些事儿, 感谢原作者分享。 不必在乎目的地,在乎的是沿途的风景以及看风景的心情,让心灵去旅行!