web分页那些事儿

关键词: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分页那些事儿

相关文章:

你感兴趣的文章:

标签云: