django基础之分页器

一:分页器

1.1 分页器基本使用

class BooksView(View):

    def get(self, request):
        # book_list = []
        # for i in range(1,101):
        #     book_obj = Book(title = 'book_%s' % i, price = random.randint(30, 200))
        #     book_list.append(book_obj)
        # Book.objects.bulk_create(book_list)
        book_list = Book.objects.all()
        paginator = Paginator(book_list, 10)            # 实例化分页器对象,参数10为每页显示多少条数据
        print('count: ', paginator.count)               # 数据总数
        print('num_pages: ', paginator.num_pages)       # 分页的总页数
        print('page_range: ', paginator.page_range)     # 页数的范围列表
        print('first page content: ', paginator.get_page(1))    # 第一页的所有数据,参数为2即为第二页的所有数据
        page2 = paginator.get_page(2)
        print(page2.has_next())                         # 是否有下一页
        print(page2.next_page_number())                 # 下一页的页码
        print(page2.has_previous())                     # 是否有上一页
        print(page2.previous_page_number())             # 上一页的页码
        return render(request, 'books.html', {'book_list': book_list})

1.2 分页导航实现

类视图:

class BooksView(View):

    def get(self, request):
        book_list = Book.objects.all()
        paginator = Paginator(book_list, 5)
        current_page = int(request.GET.get('page', 1))
        page = paginator.get_page(current_page)

        if paginator.num_pages > 11:    # 假设页面最多显示11个页码
            if current_page -5 < 1:
                page_range = range(1, 12)
            elif current_page + 5 > paginator.num_pages:
                page_range = range(paginator.num_pages - 10, paginator.num_pages)
            else:
                page_range = range(current_page - 5, current_page + 6)
        else:
            page_range = paginator.page_range

        return render(request, 'books.html', {
            # 'book_list': book_list
            'page': page,
            'paginator': paginator,
            'current_page': current_page,
            'page_range': page_range
        })

HTML页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1>Books List</h1>
<ul>
    {% for book in page %}
    <li>{{ book.title }} -- {{ book.price }}</li>
    {% endfor %}
</ul>

<nav aria-label="Page navigation">
  <ul class="pagination">

  <li><a href="?page=1">首页</a></li>

  {% if page.has_previous %}
    <li>
      <a href="?page={{ page.previous_page_number }}" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
      {% else %}
      <li class="disabled">
          <a href="javascript:void(0);" aria-label="Previous">
              <span aria-hidden="true">&laquo;</span>
          </a>
    </li>
  {% endif %}

    {% for num in page_range %}
        {% if num == current_page %}
            <li class="active"><a href="?page={{ num }}">{{ num }}</a></li>
        {% else %}
            <li><a href="?page={{ num }}">{{ num }}</a></li>
        {% endif %}
    {% endfor %}

  {% if page.has_next %}
    <li>
      <a href="?page={{ page.next_page_number }}" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  {% else %}
     <li class="disabled">
      <a href="javascript:void(0);" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  {% endif %}

  <li><a href="?page={{ paginator.num_pages }}">尾页</a></li>

  </ul>
</nav>
</body>
</html>

显示效果:
django基础之分页器

1.3 自定义分页器类

class Paginator:
    def __init__(self, request, current_page, all_count, per_page=10, max_page_num=13):
        """
        封装分页相关数据
        :param current_page:  当前页码
        :param all_count:  数据库中的数据总条数
        :param per_page:   每个页面显示的数据条数
        :param max_page_num:  最多显示的页码个数
        :param num_pages:  通过总条数/每个页面显示的条数,求出总页数
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1
        if current_page < 1:
            current_page = 1
        self.current_page = current_page
        self.all_count = all_count
        self.per_page = per_page

        # 计算总页数
        num_pages, temp = divmod(all_count, per_page)
        if temp:
            num_pages += 1
        self.num_pages = num_pages

        self.max_page_num = max_page_num  # 11
        self.page_count_half = int((self.max_page_num - 1) / 2)  # 5

        import copy
        self.url_args = copy.deepcopy(request.GET)
        print(self.url_args.urlencode())


        """
        self.num_pages=100
        per_page=8

        current_page =1     [0:8]
        current_page =2     [8:16]
        current_page =3     [16:24]
                            [(current_page-1)*per_page:current_page*per_page ]

        """

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page

    @property
    def end(self):
        return self.current_page * self.per_page

    def page_html(self):
        # 如果总页数小于self.max_page_num(最多显示的页码个数)
        if self.num_pages <= self.max_page_num:
            page_start = 1
            page_end = self.num_pages + 1
        else:
            # 如果当前页码<=页面上最多显示11/2个页码时
            if self.current_page <= self.page_count_half:
                page_start = 1
                page_end = self.max_page_num + 1
            # 如果当前页码+最多显示11/2 大于 总页数时
            elif self.current_page + self.page_count_half > self.num_pages:
                page_start = self.num_pages - self.max_page_num + 1
                page_end = self.num_pages + 1
            else:
                page_start = self.current_page - self.page_count_half
                page_end = self.current_page + self.page_count_half + 1

        page_html_list = []

        # 首页
        self.url_args['page'] = 1
        first_page = '<nav aria-label="Page navigation"><ul class="pagination"><li><a href="?%s">首页</a></li>' % (self.url_args.urlencode())
        page_html_list.append(first_page)

        # 上一页
        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="javascript:void(0);">上一页</a></li>'
        else:
            self.url_args['page'] = self.current_page - 1
            prev_page = '<li><a href="?%s">上一页</a></li>' % (self.url_args.urlencode(), )
        page_html_list.append(prev_page)

        # 显示页码
        for i in range(page_start, page_end):
            self.url_args['page'] = i
            if self.current_page == i:
                temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.url_args.urlencode(), i)
            else:
                temp = '<li><a href="?%s">%s</a></li>' % (self.url_args.urlencode(), i)
            page_html_list.append(temp)

        # 下一页
        if self.current_page >= self.num_pages:
            next_page = '<li class="disabled"><a href="javascript:void(0);">下一页</a></li>'
        else:
            self.url_args['page'] = self.current_page + 1
            next_page = '<li><a href="?%s">下一页</a></li>' % (self.url_args.urlencode(), )
        page_html_list.append(next_page)

        # 尾页
        self.url_args['page'] = self.num_pages
        last_page = '<li><a href="?%s">尾页</a></li></ul></nav>' % self.url_args.urlencode()
        page_html_list.append(last_page)

        return "".join(page_html_list)

视图层使用:

class Index(View):
    def get(self, request):        
        book_list = models.Book.objects.all()
        current_page = request.GET.get('page')
        paginator = Paginator(request, current_page, book_list.count(), 6, 11)
        book_list = book_list[paginator.start: paginator.end]

        return render(request, "index2.html", {"book_list": book_list, "paginator": paginator, "current_page": current_page})

二:ListView视图

网站开发中,经常会出现需要列出某个列表中的数据作为列表展示出来。在Django中可以使用内置的ListView来快速实现分页的需求

# models.py
class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    create_time = models.DateTimeField(auto_now_add = True)

批量生测试数据视图函数:

def articles(request):
    article_list = []
    for x in range(102):
        article = Article(title = 'title:%s' %x, content = 'content: %s' %x)
        article_list.append(article)
    Article.objects.bulk_create(article_list)	# 效率比单独的for循环要高
    return HttpResponse('OK')

数据展示视图类:

class ArticleListView(ListView):
    model = Article                         # 指定这个列表是给哪个模型类
    template_name = 'article_list.html'     # 指定使用的模板文件
    context_object_name = 'articles'        # 模型类展示到模板中上下文的名字
    paginate_by = 10                        # 每页显示多少条数据
    ordering = 'create_time'                # 按模型类中的哪个字段进行排序
    page_kwarg = 'p'                        # 分页请求参数,默认为:page
	# 以下两个方法为重写父类的方法
    def get_context_data(self, **kwargs):
        '''用于给模板传递上下文 '''
        context = super(ArticleListView, self).get_context_data(**kwargs)
        context['username'] = 'ginvip'
        print(context)
        return context

    def get_queryset(self):
        '''默认展示模型类中的所有数据,如需对展示的数据进行二次处理,在该方法中实现'''
        return Article.objects.filter(id__lte = 12)	# 这里只展示id小于等于12的数据

数据展示效果如下图:
Django ListView

三:Paginator和Page类

PaginatorPage类都是用来做分页的。他们在Django中的路径为:django.core.paginator.Paginatordjango.core.paginator.Page

扫描二维码关注公众号,回复: 9151453 查看本文章

3.1 Paginator常用属性和方法

count:总共有多少条数据
num_pages:总共有多少页
page_range:页面的区间,如有三页数据,那么就是range(1,4)

3.2 Page常用属性和方法

has_next:是否还有下一页
has_previous:是否还有上一页
next_page_number:下一页的页码
privious_page_number:上一页的页码
number:当前页
start_index:当前这一页的第一条数据的索引值
end_index:当前这一页的最后一条数据的索引值

可以在get_context_data方法中打印输出上面两个小节的各个参数

    def get_context_data(self, **kwargs):
        '''用于给模板传递上下文'''
        context = super(ArticleListView, self).get_context_data(**kwargs)
        paginator = context.get('paginator')
        page = context.get('page_obj')
        print(paginator.__dict__)
        print(page.number)
        return context

四:分页导航的实现

这里使用bootstrap来实现分页导航
分页导航样式见:https://v3.bootcss.com/components/#pagination
模板文件中引入下面一行代码即可:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

分页视图类:

class ArticleListView(ListView):
    model = Article                         # 指定这个列表是给哪个模型类
    template_name = 'article_list.html'     # 指定使用的模板文件
    context_object_name = 'articles'        # 模型类展示到模板中上下文的名字
    paginate_by = 10                        # 每页显示多少条数据
    ordering = 'create_time'                # 按模型类中的哪个字段进行排序
    page_kwarg = 'p'                        # 分页请求参数,默认为:page

    def get_context_data(self, **kwargs):
        '''用于给模板传递上下文'''
        context = super(ArticleListView, self).get_context_data(**kwargs)
        return context
    # 为了实现分页效果,这里展示所有数据,所以注释掉了get_queryset(self)方法

视图模板文件内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<ul>
    {% for foo in articles %}
        <li>{{ foo.title }}</li>
    {% endfor %}
    <ul class="pagination">
        {# 判断是否有上一页 #}
        {% if page_obj.has_previous %}
            <li><a href="{% url 'book:list' %}?p={{ page_obj.previous_page_number }}">上一页</a></li>
            {% else %}
            <li class="disabled"><a href="javascript:void(0);">上一页</a></li>
        {% endif %}

        {# 中间的页码 #}
        {% for page in paginator.page_range %}
            {% if page == page_obj.number %}
                <li class="active"><a href="javascript:void(0);">{{ page }}</a></li>
                {% else %}
                <li><a href="{% url 'book:list' %}?p={{ page }}">{{ page }}</a></li>
            {% endif %}
        {% endfor %}

        {# 下一页 #}
        {% if page_obj.has_next %}
            <li><a href="{% url 'book:list' %}?p={{ page_obj.next_page_number }}">下一页</a></li>
            {% else %}
            <li class="disabled"><a href="javascript:void(0);">下一页</a></li>
        {% endif %}
    </ul>
</ul>

</body>
</html>

分页导航展示效果如下:
Django2.0 分页导航
基本实现了分页导航的效果,但是有一个问题,就是分页区间的展示是展示了所有的页码
分页视图类:

class ArticleListView(ListView):
    model = Article                         # 指定这个列表是给哪个模型类
    template_name = 'pagination.html'     # 指定使用的模板文件
    context_object_name = 'articles'        # 模型类展示到模板中上下文的名字
    paginate_by = 10                        # 每页显示多少条数据
    ordering = 'create_time'                # 按模型类中的哪个字段进行排序
    page_kwarg = 'p'                        # 分页请求参数,默认为:page

    def get_context_data(self, **kwargs):
        '''用于给模板传递上下文'''
        context = super(ArticleListView, self).get_context_data(**kwargs)
        paginator = context.get('paginator')
        page_obj = context.get('page_obj')
        pagination_data = self.get_pagination_data(paginator, page_obj, 2)
        context.update(pagination_data)
        return context

    def get_pagination_data(self, paginator, page_obj, around_count = 2):
        current_page = page_obj.number
        total_pages = paginator.num_pages
        left_has_more = False
        right_has_more = False

        if current_page <= around_count + 2:
            left_pages = range(1,current_page)
        else:
            left_has_more = True
            left_pages = range(current_page - around_count, current_page)

        if current_page >= total_pages - around_count - 1:
            right_pages = range(current_page + 1, total_pages + 1)
        else:
            right_has_more = True
            right_pages = range(current_page + 1, current_page + around_count + 1)

        return {
            'left_pages': left_pages,
            'right_pages': right_pages,
            'current_page': current_page,
            'left_has_more': left_has_more,
            'right_has_more': right_has_more,
            'total_pages': total_pages
        }

模板文件内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<ul>
    {% for foo in articles %}
        <li>{{ foo.title }}</li>
    {% endfor %}
    <ul class="pagination">
        {# 判断是否有上一页 #}
        {% if page_obj.has_previous %}
            <li><a href="{% url 'book:list' %}?p={{ page_obj.previous_page_number }}">上一页</a></li>
            {% else %}
            <li class="disabled"><a href="javascript:void(0);">上一页</a></li>
        {% endif %}

        {% if left_has_more %}
            <li><a href="{% url 'book:list' %}?p=1">1</a></li>
            <li><a href="javascript:void(0);">...</a></li>
        {% endif %}
        {# 左边的页码 #}
        {% for left_page in left_pages %}
            <li><a href="{% url 'book:list' %}?p={{ left_page }}">{{ left_page }}</a></li>
        {% endfor %}
        {# 当前的页码 #}
        <li class="active"><a href="{% url 'book:list' %}?p={{ current_page }}">{{ current_page }}</a></li>


        {# 右边的页码 #}
        {% for right_page in right_pages %}
            <li><a href="{% url 'book:list' %}?p={{ right_page }}">{{ right_page }}</a></li>
        {% endfor %}
        {% if right_has_more %}
            <li><a href="javascript:void(0);">...</a></li>
            <li><a href="{% url 'book:list' %}?p={{ total_pages }}">{{ total_pages }}</a></li>
        {% endif %}

        {# 下一页 #}
        {% if page_obj.has_next %}
            <li><a href="{% url 'book:list' %}?p={{ page_obj.next_page_number }}">下一页</a></li>
            {% else %}
            <li class="disabled"><a href="javascript:void(0);">下一页</a></li>
        {% endif %}
    </ul>
</ul>

</body>
</html>

最终效果:
Django ORM

发布了45 篇原创文章 · 获赞 3 · 访问量 1541

猜你喜欢

转载自blog.csdn.net/pcn01/article/details/102659255
今日推荐