Django 分页
1.django分页
django分页功能,有专门的分页辅助类Paginator,Page
Paginator
class Paginator(object):
def __init__(self, object_list, per_page, orphans=0,
allow_empty_first_page=True):
self.object_list = object_list
self.per_page = int(per_page)
self.orphans = int(orphans)
self.allow_empty_first_page = allow_empty_first_page
self._num_pages = self._count = None
- Paginator.page(number):根据参数number返回一个Page对象
- Pagnator.num_pages:页面总数
- pagiator.page_range:页面范围,列表,从1开始,例如[1,2,3,4]
- Paginator.count:所有页面对象总数,即统计object_list中item数目
Page
class Page(collections.Sequence):
def __init__(self, object_list, number, paginator):
self.object_list = object_list
self.number = number
self.paginator = paginator
Page.has_next
() 如果有下一页,则返回True。Page.has_previous
() 如果有上一页,返回 True。Page.has_other_pages
() 如果有上一页或下一页,返回True。Page.next_page_number
() 返回下一页的页码。如果下一页不存在,抛出InvlidPage异常。Page.previous_page_number
() 返回上一页的页码。如果上一页不存在,抛出InvalidPage异常。Page.start_index
() 返回当前页上的第一个对象,相对于分页列表的所有对象的序号,从1开始。比如,将五个对象的列表分为每页两个对象,第二页的start_index()会返回3。-
Page.end_index
() 返回当前页上的最后一个对象,相对于分页列表的所有对象的序号,从1开始。 比如,将五个对象的列表分为每页两个对象,第二页的end_index() 会返回 4。 - Page.object_list 当前页上所有对象的列表。
- Page.number 当前页的序号,从1开始。
- Page.paginator 相关的Paginator对象。页面中使用很方便
非法页面处理
-
InvalidPage(Exception): 异常的基类,当paginator传入一个无效的页码时抛出。 Paginator.page()放回在所请求的页面无效(比如不是一个整数)时,或者不包含任何对象时抛出异常。通常,捕获InvalidPage异常就够了,但是如果你想更加精细一些,可以捕获以下两个异常之一:
- exception PageNotAnInteger,当向page()提供一个不是整数的值时抛出。
- exception EmptyPage,当向page()提供一个有效值,但是那个页面上没有任何对象时抛出。
这两个异常都是InalidPage的子类,所以可以通过简单的except InvalidPage来处理它们。
基本语法实例
import os
from django.core.paginator import Paginator
objects = ['john','paul','george','ringo','lucy','meiry','checy','wind','flow','rain']<br>
p = Paginator(objects,3) # 3条数据为一页,实例化分页对象
print p.count # 10 对象总共10个元素
print p.num_pages # 4 对象可分4页
print p.page_range # xrange(1, 5) 对象页的可迭代范围
page1 = p.page(1) # 取对象的第一分页对象
print page1.object_list # 第一分页对象的元素列表['john', 'paul', 'george']
print page1.number # 第一分页对象的当前页值 1
page2 = p.page(2) # 取对象的第二分页对象
print page2.object_list # 第二分页对象的元素列表 ['ringo', 'lucy', 'meiry']
print page2.number # 第二分页对象的当前页码值 2
print page1.has_previous() # 第一分页对象是否有前一页 False
print page1.has_other_pages() # 第一分页对象是否有其它页 True
print page2.has_previous() # 第二分页对象是否有前一页 True
print page2.has_next() # 第二分页对象是否有下一页 True
print page2.next_page_number() # 第二分页对象下一页码的值 3
print page2.previous_page_number() # 第二分页对象的上一页码值 1
print page2.start_index() # 第二分页对象的元素开始索引 4
print page2.end_index() # 第2分页对象的元素结束索引 6
2.实例代码
#index.html
_{_% block content _%_}
_{_% if blogs _%_}
<div class="articles">
<ul xmlns="http://www.w3.org/1999/html">
_{_% for blog in blogs _%_}
<li><a href=" _{_% url 'timeblog:detail' blog.id _%_}"> _{_{ blog.title _}_}</a></li>
_{_% endfor _%_}
</ul>
</div>
_{_% endif _%_}
_{_% endblock content _%_}
_{_% block paginator _%_}
_{_% if blogs.paginator.num_pages > 1 _%_}
<div class="paginator">
_{_% if blogs.has_previous _%_}
<a class="pre" href="?page=_{_{ blogs.previous_page_number _}_}">« 上一页</a>
_{_% endif _%_}
_{_% for pg in blogs.paginator.page_range _%_}
_{_% if pg == blogs.number _%_}
<span class="current"><a href="?page=_{_{ blogs.number _}_}"> _{_{ blogs.number _}_} </a></span>
_{_% else _%_}
<span class="items"><a href="?page=_{_{ pg _}_}"> _{_{ pg _}_} </a></span >
_{_% endif _%_}
_{_% endfor _%_}
_{_% if blogs.has_next _%_}
<a class="next" href="?page=_{_{ blogs.next_page_number _}_}">下一页 »</a>
_{_% endif _%_}
</div>
_{_% endif _%_}
_{_% endblock paginator _%_}
#view.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
class IndexView(generic.ListView):
template_name='timeblog/index.html'
context_object_name='blogs'
numPerpage = 5
paginator = Paginator(BlogPost.objects.order_by('-pub_date'), numPerpage)
def get_queryset(self):
"""Return the last five published questions."""
return self.request.GET.get(1)
def get_context_data(self,**kwargs):
"""Return the last five published questions."""
context = super(IndexView, self).get_context_data(**kwargs)
context['site'] = Site.objects.first()
# 分页功能
page = self.request.GET.get('page')
print(page)
try:
context['blogs'] = self.paginator.page(page)
# todo: 注意捕获异常
except PageNotAnInteger:
# 如果请求的页数不是整数, 返回第一页。
context['blogs'] = self.paginator.page(1)
except EmptyPage:
# 如果请求的页数不在合法的页数范围内,返回结果的最后一页。
context['blogs'] = self.paginator.page(self.paginator.num_pages)
return context
生成摘要
- 使用 truncatechars 模板过滤器
在 Django 的模板系统中,模板变量器的使用语法为 {{ var | filter: arg }}。可以将模板过滤看做一个函数,它会作用于被它作用的模板变量,从而改变模板变量的值。例如这里的 truncatechars 过滤器可以截取模板变量值的前 N 个字符显示。 |
例如摘要效果,需要显示 post.body 的前 54 的字符,那么可以在模板中使用 {{ post.body | truncatechars:54 }}。 |
- 复写 save 方法
- 第一种方法是通过复写模型的 save 方法,从正文字段摘取前 N 个字符保存到摘要字段。假设我们的博客文章模型为:
其中 body 字段存储的是正文,excerpt 字段用于存储摘要。通过复写模型的 save 方法,在数据被保存到数据库前,先从 body 字段摘取 N 个字符保存到 excerpt 字段中,从而实现自动摘要的目的。具体代码如下:
from django.utils.html import strip_tags
class Post(models.Model):
# 其它字段...
body = models.TextField()
excerpt = models.CharField(max_length=200, blank=True)
# 其它方法...
def save(self, *args, **kwargs):
# 从 body 摘取前 54 个字符赋给到 excerpt
if not self.excerpt:
# 实例化md,用于渲染body文本
md = markdown.Markdown(extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
])
# 将md文本渲染成html
# strip_tags 去掉html文本的全部html标签
# 摘取body前54个给excerpt
self.excerpt = strip_tags(md.convert(self.content))[:180]
# 调用父类的 save 方法将数据保存到数据库中
super(Post, self).save(*args, **kwargs) 然后在模板中适当的地方使用模板标签引用 _{_{ post.excerpt _}_} 显示摘要的值即可。
参考: