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 _}_}">&laquo; 上一页</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 _}_}">下一页 &raquo;</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 _}_} 显示摘要的值即可。

参考:

  1. my coding.net
  2. https://blog.csdn.net/u011300580/article/details/56011564
  3. https://www.cnblogs.com/kongzhagen/p/6640975.html
  4. https://www.cnblogs.com/king-lps/p/7324821.html