Job Search Engine
936 浏览 5 years, 10 months
2.10 分页功能
版权声明: 转载请注明出处 http://www.codingsoho.com/分页功能
django 参考文档 https://docs.djangoproject.com/en/1.11/topics/pagination/
后端
class JobEntryListView(ListView):
model = JobEntry
filter_class = JobEntryFilter
def get_context_data(self, *args, **kwargs):
context = super(JobEntryListView, self).get_context_data(*args, **kwargs)
...
object_list= self.filter_class(self.request.GET, self.get_queryset()).qs
# pagination
# remove page related query from GET
getvars = self.request.GET.copy()
if 'page' in getvars:
del getvars['page']
if 'pagenum_perpage' in getvars:
del getvars['pagenum_perpage']
if len(getvars.keys()) > 0:
context['getvars'] = "&%s" % getvars.urlencode()
else:
context['getvars'] = ''
# set page number per page
pagenum_perpage = self.request.GET.get('pagenum_perpage', None)
if pagenum_perpage and pagenum_perpage.isdigit():
pagenum_perpage = int(pagenum_perpage)
else:
pagenum_perpage = 10
# get record for current page
paginator = Paginator(object_list, pagenum_perpage)
records = None
page = self.request.GET.get('page')
try:
records = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
records = paginator.page(1)
page = 1
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
records = paginator.page(paginator.num_pages)
page = paginator.num_pages
# page related value
page_value = int(page)
context["start"] = pagenum_perpage*(page_value-1) + 1
context["end"] = pagenum_perpage * page_value if not page == paginator.num_pages else object_list.count()
context["total"] = object_list.count()
context["total_page"] = paginator.num_pages
display_pages = []
for page in range(1,6):
ipage = ((page_value-1)/5)*5 + page
if not ipage > paginator.num_pages:
display_pages.append(ipage)
else:
break
context["pages"] = display_pages
context["page_highlight"] = page_value
context["page"] = page_value if page_value else page
context["pagenum_perpage"] = pagenum_perpage
# new object_list
context["object_list"] = records.object_list
context["records"] = records
return context
有几个变量先搞清楚
- 当前页号 page
- 每页显示条目数 num_perpage
- 总共页数 total_page
- 总共记录号 total
- 当前显示出来可以快捷访问的页 pages
- 当前显示出来的起始页 start
- 当前显示出来的最后页 end
实现时,我们首先通过paginator = Paginator(object_list, num_perpage)
获取paginator对象,然后通过paginator.page(page)
返回记录。
正常情况下,直接将这个返回值传递给模板就可以迭代访问了。但是当前做时一直不行,我就直接返回它的变量records.object_list
了。
前端代码
{% load i18n staticfiles %}
<div class="row">
<div class="col-sm-5">
<div class="dataTables_info" id="example2_info" role="status" aria-live="polite">{% blocktrans %}Showing {{start}} to {{end}} of {{total}} entries{% endblocktrans %}</div>
<form method="GET" action="" style="float: left;">
<label>{% trans "each page" %}
<select name="pagenum_perpage" " class="input-sm?">
<option value="10" {% if pagenum_perpage == 10 %}selected{% endif %}>10</option>
<option value="25" {% if pagenum_perpage == 25 %}selected{% endif %}>25</option>
<option value="50" {% if pagenum_perpage == 50 %}selected{% endif %}>50</option>
<option value="100" {% if pagenum_perpage == 100 %}selected{% endif %}>100</option>
</select> {% trans 'entries' %}
</label>
<input id="id_des_page" name="page" type="text" value="{{page}}" style="width: 50px; text-align: center;"> / {{total_page}}{% trans 'Page' %}
<input type='submit' class='btn btn-primary' value="{% trans 'Go!' %}">
</form>
</div>
<div class="col-sm-7">
<div class="dataTables_paginate paging_simple_numbers pull-right" id="example2_paginate" >
<ul class="pagination" style="margin: 0px;">
<li class="paginate_button previous {% if not object_list.has_previous %}disabled{% endif %}" id="example2_previous">
<a href="{% if object_list.has_previous %}?page={{ object_list.previous_page_number }}&pagenum_perpage={{pagenum_perpage}}{% endif %}{{getvars}}" aria-controls="example2" data-dt-idx="0" tabindex="0">{% trans 'previous' %}</a>
</li>
{% for page in pages %}
<li class="paginate_button {% if page == page_highlight %}active{% endif %}">
<a href="?page={{page}}&pagenum_perpage={{pagenum_perpage}}{{getvars}}" aria-controls="example2" data-dt-idx="{{forloop.count}}" tabindex="0">{{page}}</a>
</li>
{% endfor %}
<li class="paginate_button next {% if not object_list.has_next %}disabled{% endif %}" id="example2_next">
<a href="{% if object_list.has_next %}?page={{ object_list.next_page_number }}&pagenum_perpage={{pagenum_perpage}}{% endif %}{{getvars}}" aria-controls="example2" data-dt-idx="7" tabindex="0">{% trans 'next' %}</a>
</li>
</ul>
</div>
</div>
</div>
有几个地方要叙述一下
- has_previous , has_next 用于判断是否是第一页和最后一页,来决定如何显示“前一页”和“后一页”这两个超链接
- blocktrans 这儿我们用到了国际化的另一个应用,
{% blocktrans %}Showing {{start}} to {{end}} of {{total}} entries{% endblocktrans %}
支持字符和数字变量的混写。
混入类 mixin
分页是一个最基本的功能,在每一个类中都写一遍是非常低效的,这儿我们将引入混入类的用法,把分页功能抽象出来
添加包plugin,添加文件mixins.py
将刚才的页面处理函数添加到下面函数
class PageMixin(object):
def get_context_data(self, *args, **kwargs):
创建新文件pages.html,将刚才的前端代码都放进去。
修改JobEntryListView类,添加基类PageMixin,同时注意在调用super之前将filter之后的object_list传递给它
class JobEntryListView(PageMixin, ListView):
def get_context_data(self, *args, **kwargs):
object_list= self.filter_class(self.request.GET, self.get_queryset()).qs
kwargs.update({'object_list':object_list}) # without this, Paginator will get full object_list for handle
context = super(JobEntryListView, self).get_context_data(*args, **kwargs)
# context['object_list'] = self.filter_class(self.request.GET, self.get_queryset()).qs
...
这样,分页功能就完成了。
django-pagination库
这个库使用起来非常简单,具体可参考django-pagination
从文件pagination_tags.py看,它有页面的一些相关配置
DEFAULT_PAGINATION = getattr(settings, 'PAGINATION_DEFAULT_PAGINATION', 20)
DEFAULT_WINDOW = getattr(settings, 'PAGINATION_DEFAULT_WINDOW', 4)
DEFAULT_ORPHANS = getattr(settings, 'PAGINATION_DEFAULT_ORPHANS', 0)
INVALID_PAGE_RAISES_404 = getattr(settings,
'PAGINATION_INVALID_PAGE_RAISES_404', False)
也可以重写模板文件,美化界面。
后面有时间,我打算把上面的模板方法也写成templatetag,这样更加方便在模板中使用。