最近在项目中使用到了Django自带的分页功能,并结合Bootstrap的分页样式制作了分页条,在这里把使用心得和大家做一下分享。
分页功能效果如下图:
使用Django自带的分页功能,我们可以直接定义视图时继承“ListView”类,并设置相关类变量。
class OrderView(ListView): model = Order # 模型类 template_name = 'order.html' # 模板名称 paginate_by = 20 # 每页数量
当完成上述代码后,我们就可以使用Django自带的分页功能了。
分页条模板代码如下:
<ul class="pagination pull-right"> <!--如果有前一页--> {% if page_obj.has_previous %} <!--如果有前一页--> <li><a href="./?page=1">首页</a></li><!--链接到首页--> <li><a href="./?page={{ page_obj.previous_page_number }}">«</a></li> <!--链接到前一页页码--> {% else %}<!--否则--> <li class="disabled"><a>首页</a></li> <!--禁用首页按钮--> <li class="disabled"><a>«</a></li> <!--禁用前一页按钮--> {% endif %} {% for page_number in paginator.page_range %} <!--遍历页码范围--> {% if page_number != page_obj.number %} <!--如果页码与当前页页码不相同--> <li><a href="./?page={{ page_number }}">{{ page_number }}</a></li> <!--生成页码并添加链接--> {% else %} <li class="active"><a>{{ page_number }}</a></li> <!--否则,呈现激活样式--> {% endif %} {% endfor %} {% if page_obj.has_next %} <!--如果有下一页--> <li><a href="./?page={{ page_obj.next_page_number }}">»</a></li> <!--链接到下一页页码--> <li><a href="./?page={{ paginator.num_pages }}">尾页</a></li> <!--链接到尾页--> {% else %}<!--否则--> <li class="disabled"><a>»</a></li> <!--否则禁用下一页按钮--> <li class="disabled"><a>尾页</a></li> <!--禁用尾页按钮--> {% endif %} </ul>
上方代码中,有一些关键的内容如下:
- paginator.page_range:页码范围(迭代对象)
- page_obj.has_previous:是否存在前一页(布尔值)
- page_obj.has_next:是否存在下一页(布尔值)
- page_obj.previous_page_number:前一页的页码(数值)
- page_obj.next_page_number:下一页的页码(数值)
- page_obj.number:当前页的页码(数值)
- paginator.num_pages:页面总数量(数值)
如果只是想实现首页、尾页、上一页、下一页以及根据页码翻页的功能,上面的代码就能够满足需求了。
不过,往往我们的项目中会包含很多数据,分页总数量很多,这个时候分页条会变得很长。
所以,我们需要在分页条中只显示部分页码,就像效果图一样,无论当前为第几页,且无论有多少页码,分页条上不超过9个数字页码,规则如下:
- 当前页码为前4页并且读取到的页码为前9页时,分页条上加载读取到的页码。
- 当前页码为后4页并且读取到的页码为后9页时,分页条上加载读取到的页码。
- 读取到的页码为当前页码前4页与后4页之间的页码时,分页条上加载读取到的页码。
根据以上规则,我们可以添加相应的条件判断,让页码有条件的在分页条上显示出来。
这里我们需要在模板中对页码进行加减法运算,需要用到Django自带的过滤器“add”。
过滤器“add”的使用方法为:{{ 变量|add:”x”}},能够对变量进行加减一定数值的操作,“x”表示加减的数值,正数为加法,负数为减法。
所以上面的规则写成条件如下:
- page_obj.number < 5 and page_number < 10
- page_number|add:”9″ > paginator.num_pages and page_obj.number|add:”4″ > paginator.num_pages
- page_number|add:”5″ > page_obj.number and page_number|add:”-5″ < page_obj.number
这三个条件是“或者”的关系,我们可以在模板代码中使用“or”进行连接。
新的分页条代码如下:
<ul class="pagination pull-right">
{% if page_obj.has_previous %} <!--如果有前一页-->
<li><a href="./?page=1">首页</a></li><!--链接到首页-->
<li><a href="./?page={{ page_obj.previous_page_number }}">«</a></li><!--链接到前一页页码-->
{% else %}<!--否则-->
<li class="disabled"><a>首页</a></li><!--禁用首页按钮-->
<li class="disabled"><a>«</a></li><!--禁用前一页按钮-->
{% endif %}
{% for page_number in paginator.page_range %}<!--遍历页码范围-->
{% if page_number != page_obj.number %}<!--如果页码与当前页页码不相同-->
{% if page_obj.number < 5 and page_number < 10 or page_number|add:"9" > paginator.num_pages and page_obj.number|add:"4" > paginator.num_pages or page_number|add:"5" > page_obj.number and page_number|add:"-5" < page_obj.number %}
<li><a href="./?page={{ page_number }}">{{ page_number }}</a></li><!--生成页码并添加链接-->
{% endif %}
{% else %}
<li class="active"><a>{{ page_number }}</a></li><!--否则,呈现激活样式-->
{% endif %}
{% endfor %}
{% if page_obj.has_next %}<!--如果有下一页-->
<li><a href="./?page={{ page_obj.next_page_number }}">»</a></li><!--链接到下一页页码-->
<li><a href="./?page={{ paginator.num_pages }}">尾页</a></li><!--链接到尾页-->
{% else %}<!--否则-->
<li class="disabled"><a>»</a></li><!--否则禁用下一页按钮-->
<li class="disabled"><a>尾页</a></li><!--禁用尾页按钮-->
{% endif %}
</ul>
对于一般的列表分页来说,上面的代码已经能够满足需求。
不过,如果我们通过“GET”方式传递参数,对列表进行筛选排序的操作时,如果不对分页条代码进行处理,那么翻页之后会发现筛选排序失效。
因为,我们的分页条中组织的翻页链接没有带上相应的参数。
例如,我们筛选当日订单时,URL为:http://www.domain.com/admin/order/?create_time=today。
而点击翻页按钮之后(例如翻到第2页),此时URL为:http://www.domain.com/admin/order/?page=2。
这时丢失了参数“create_time=today”,所以我们翻页后,列表是所有订单,而不是当日订单。
那么,怎么在设置分页链接的时候,带有前一次URL中的参数呢?
我们可以在视图中通过“request.META.get(‘QUERY_STRING’, None)”获取上一次的参数,然后传入模板中。
示例代码:
query_string = re.sub(r'page=[0-9]+[&]?', '', request.META.get('QUERY_STRING', None)) # 替换掉请求参数中的页码参数及其后方的“&”符号 if query_string: # 如果还有其他参数 query_string = '&' + query_string # 将其他参数前方添加“&”符号
通过上方的代码我们就能够获得上一次URL中的请求参数,然后将获取到的请求参数和列表筛选结果一起传递给模板就可以了。
最终模板中分页条代码为:
<ul class="pagination pull-right"> {% if page_obj.has_previous %} <!--如果有前一页--> <li><a href="./?page=1{{ query_string }}">首页</a></li><!--链接到首页--> <li><a href="./?page={{ page_obj.previous_page_number }}{{ query_string }}">«</a></li><!--链接到前一页页码--> {% else %}<!--否则--> <li class="disabled"><a>首页</a></li><!--禁用首页按钮--> <li class="disabled"><a>«</a></li><!--禁用前一页按钮--> {% endif %} {% for page_number in paginator.page_range %}<!--遍历页码范围--> {% if page_number != page_obj.number %}<!--如果页码与当前页页码不相同--> {% if page_obj.number < 5 and page_number < 10 or page_number|add:"9" > paginator.num_pages and page_obj.number|add:"4" > paginator.num_pages or page_number|add:"5" > page_obj.number and page_number|add:"-5" < page_obj.number %} <li><a href="./?page={{ page_number }}{{ query_string }}">{{ page_number }}</a></li><!--生成页码并添加链接--> {% endif %} {% else %} <li class="active"><a>{{ page_number }}</a></li><!--否则,呈现激活样式--> {% endif %} {% endfor %} {% if page_obj.has_next %}<!--如果有下一页--> <li><a href="./?page={{ page_obj.next_page_number }}{{ query_string }}">»</a></li><!--链接到下一页页码--> <li><a href="./?page={{ paginator.num_pages }}{{ query_string }}">尾页</a></li><!--链接到尾页--> {% else %}<!--否则--> <li class="disabled"><a>»</a></li><!--否则禁用下一页按钮--> <li class="disabled"><a>尾页</a></li><!--禁用尾页按钮--> {% endif %} </ul>
转载请注明:魔力Python » Django项目中使用自带的分页功能