在做网页的过程中,随着展示的数据增多,如果要在一页中显示全部内容,浏览速度会变慢且不符合实际需求。在 Web 浏览器中, 内容多的网页需要花费更多的时间生成、下载和渲染, 所以网页内容变多会降低用户体验的质量。这一问题的解决方法是分页显示数据,进行片段式渲染。
在页面中渲染数据
<span style="font-size:18px;">app/main/views.py</span> @main.route('/userManage_admin', methods=['GET', 'POST']) @login_required def userManage_admin(): user0 = User.query.filter_by(email=current_user.email).first() <strong>page = request.args.get('page', 1, type=int)</strong> if user0.user_role > 0: <strong>pagination = User.query.filter_by(user_role=0).paginate(page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'], error_out=False) usrs = pagination.items</strong> return render_template('userManage_admin.html', <strong>usrs=usrs,pagination=pagination</strong>) else: return redirect(url_for('.index'))
渲染的页数从请求的查询字符串( request.args)中获取,如果没有明确指定,则默认渲染第一页。参数 type=int 保证参数无法转换成整数时,返回默认值。为了显示某页中的记录, 要把 all() 换成 Flask-SQLAlchemy 提供的 paginate() 方法。页数是 paginate() 方法的第一个参数,也是唯一必需的参数。可选参数 per_page 用来指定每页显示的记录数量; 如果没有指定,则默认显示 20 个记录。另一个可选参数为 error_out,当其设为 True
时(默认值),如果请求的页数超出了范围,则会返回 404 错误;如果设为 False,页数超出范围时会返回一个空列表。为了能够很便利地配置每页显示的记录数量,参数 per_page 的值从程序的环境变量 FLASKY_POSTS_PER_PAGE 中读取。这样修改之后, 页面中的内容列表只会显示有限数量的信息。若想查看第 2 页中的信息,要在浏览器地址栏中的 URL 后加上查询字符串 ?page=2。
添加分页导航
paginate() 方法的返回值是一个 Pagination 类对象,这个类在 Flask-SQLAlchemy 中定义。这个对象包含很多属性, 用于在模板中生成分页链接,因此将其作为参数传入了模板。
分页对象的属性简介
在Flask-SQLAlchemy对象上可调用的方法
拥有这么强大的对象和 Bootstrap 中的分页 CSS 类,我们很轻易地就能在模板底部构建一个分页导航。
如下是以 Jinja2 宏的形式实现的分页导航。
<span style="font-size:18px;">app/templates/_macros.html:分页模板宏 </span>{% macro pagination_widget(pagination, endpoint) %} <ul class="pagination"> <li{% if not pagination.has_prev %} class="disabled"{% endif %}> <a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.prev_num, **kwargs) }}{% else %}#{% endif %}"> « </a> </li> {% for p in pagination.iter_pages() %} {% if p %} {% if p == pagination.page %} <li class="active"> <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{ p }}</a> </li> {% else %} <li> <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{ p }}</a> </li> {% endif %} {% else %} <li class="disabled"><a href="#">…</a></li> {% endif %} {% endfor %} <li{% if not pagination.has_next %} class="disabled"{% endif %}> <a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.next_num, **kwargs) }}{% else %}#{% endif %}"> » </a> </li> </ul> {% endmacro %}
这个宏创建了一个 Bootstrap 分页元素,即一个有特殊样式的无序列表,其中定义了下述页面链接。
? “上一页”链接。如果当前页是第一页,则为这个链接加上 disabled 类。
? 分页对象的 iter_pages() 迭代器返回的所有页面链接。这些页面被渲染成具有明确页数的链接,页数在 url_for() 的参数中指定。当前显示的页面使用 activeCSS 类高亮显示。页数列表中的间隔使用省略号表示。
? “下一页”链接。如果当前页是最后一页,则会禁用这个链接。
Jinja2 宏的参数列表中不用加入 **kwargs 即可接收关键字参数。分页宏把接收到的所有关键字参数都传给了生成分页链接的 url_for() 方法。这种方式也可在路由中使用,例如包含一个动态部分的资料页。
pagination_widget 宏可放在其他一些模板的后面。
<span style="font-size:18px;">app/templates/useManage_admin.html <span style="font-size:18px;">在学生信息列表下面添加分页导航</span></span> {% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% import "_macros.html" as macros %} {% block main %} {{ super() }} <div class="main"> .....................中间省略要显示的内容 {% if pagination %} {{ macros.pagination_widget(pagination, '.sm_admin') }} {% endif %} </div> {% endblock %}