django分页

Django作为Python Web开发框架的一哥,提供了企业级网站开发所需要的几乎所有功能,其中就包括自带分页功能。利用Django自带的Paginator类,我们可以很轻松地实现分页。Django 2.0和1.X最大的不同在于新增了get_page()方法。我们现在来具体看看有什么不同。

 

Django 1.X 和Django 2.0下实现分页

 

利用Django实现分类非常简单,我们只需要修改views.py和模板template。Django 1.X下实现分页代码如下:

# app/views.py - 基于函数的视图

 

 1 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 2 from .models import Article
 3 from django.shortcuts import render
 4 
 5 def article_list(request):
 6     article_list = Article.objects.all()
 7     paginator = Paginator(article_list, 10)  # 实例化一个分页对象, 每页显示10个
 8 
 9     page = request.GET.get('page')  # 从URL通过get页码,如?page=3
10     try:
11         articles = paginator.page(page)  # 获取某页对应的记录
12     except PageNotAnInteger:  # 如果页码不是个整数
13         articles = paginator.page(1)  # 提取第一页的记录
14     except EmptyPage:  # 如果页码太大,没有相应的记录
15         articles = paginator.page(paginator.num_pages)  # 提取最后一页的记录
16 
17     return render(request, 'article_list.html', {'articles': articles})
View Code

你注意到没有?上段代码的try和2个except非常重要,但是看上去有些冗余。Django 2.0下新增了get_page()方法,可以将代码大大简化(如下图所示)。它所实现的功能与上面是一样的。当用户提交的页码不是整数时,提取第一页记录。当用户输入的页码太大时,只提取最后一页记录。

 1 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 2 from .models import Article
 3 from django.shortcuts import render
 4 
 5 def article_list(request):
 6     article_list = Article.objects.all()
 7     paginator = Paginator(article_list, 10)  # 实例化一个分页对象, 每页显示10个
 8 
 9     page = request.GET.get('page')  # 从URL通过get页码,如?page=3
10    articles = paginator.get_page(page)  # 获取某页对应的记录, 如果
11     
12     return render(request, 'article_list.html', {'articles': articles})
View Code

Django 1.X和2.0下的模板是一样的。这里提供两种显示方案。

模板一: 上一页, Page 1 of 3, 下一页

#app/templates/app/article_list.html

 1 {% for article in articles %} 
 2     {{ article.title }}  
 3 {% endfor %}
 4 
 5 <div class="pagination">
 6     <span class="step-links">
 7         {% if articles.has_previous %}
 8             <a href="?page=1">&laquo; first</a>
 9             <a href="?page={{ articles.previous_page_number }}">previous</a>
10         {% endif %}
11 
12         <span class="current">
13             Page {{ articles.number }} of {{ articles.paginator.num_pages }}.
14         </span>
15 
16         {% if articles.has_next %}
17             <a href="?page={{ articles.next_page_number }}">next</a>
18             <a href="?page={{ articles.paginator.num_pages }}">last &raquo;</a>
19         {% endif %}
20     </span>
21 </div>
View Code

模板二: Page 1, 2, 3, 4, 5, 6, 7, 8, ... (推荐)

#app/templates/app/article_list.html

 1 # Pagination style 2
 2 {% for article in articles %}
 3     {{ article.title }}
 4 {% endfor %}
 5 <div class="pagination">
 6 <nav>
 7     <ul class="pagination">
 8         {% if articles.has_previous %}
 9         <li class="">
10         <a href="?page={{ articles.previous_page_number }}" aria-label="Previous">
11         <span aria_hidden="true">&laquo;</span></a>
12         </li>
13         {% endif %}
14         
15         {% for page_num in articles.paginator.page_range %}
16             {% if page_num == articles.number %}
17          <li class="active"><a href="?page={{ page_num }}">{{page_num}}</a> </li>
18             {% else %}
19          <li class=""><a href="?page={{ page_num }}">{{page_num}}</a> </li>
20             {% endif %}
21         {% endfor %}
22         
23         {% if articles.has_next %}
24          <li class="">
25               <a href="?page={{ articles.next_page_number }}" aria-label="Next">
26                   <span aria_hidden="true">&raquo;</span></a>
27         </li>
28       {% endif %}
29     </ul>
30 </nav>
31 </div>
View Code

Django如何在基于类的视图里使用分页?

 

上述案例里我们使用了函数试图,很容易定义page对象, 并传递给模板,例如articles。但是如果我们希望使用基于类的视图,我们该如何实现分页呢?其实操作非常简单。我们只需在视图中加入paginate_by = number即可。

from. models import Article
from django.views.generic import ListView

class ArticleListView(ListView):
    model = Article  # 等于 queryset = models.Article.objects.all()
    template_name = 'app/article_list.html'  # 可选的
    context_object_name = "article_list"    # 默认context名字
    paginate_by = 10  # 每页10项
View Code

此时模板article_list.html也需要做出相应调整,如下图所示。Django会先对是否分页is_paginated做个判断,如果有,就会自动生成个page_obj分页对象传递到模板。

 1 {% if article_list %}
 2     {% for article in article_list %}
 3     {{ article.title }}
 4     {% endfor %}
 5 
 6     {% if is_paginated %}
 7     <ul class="pagination">
 8     {% if page_obj.has_previous %}
 9     <li>
10         <span><a href="?page={{ page_obj.previous_page_number }}">Previous</a></span>
11     </li>
12     {% endif %}
13     <li class="">
14         <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
15     </li>
16     {% if page_obj.has_next %}
17           <li>
18         <span><a href="?page={{ page_obj.next_page_number }}">Next</a></span>
19     </li>
20     {% endif %}
21     </ul>
22 
23 {% else %}
24     <h3>Articles</h3>
25     <p>No article yet</p>
26 {% endif %}
View Code

django自定义分页

未封装版:

  • 优点:直观
  • 缺点:代码乱,不易维护,可拓展性差
     1 data = []
     2  
     3 for i in range(1, 302):
     4     tmp = {"id": i, "name": "alex-{}".format(i)}
     5     data.append(tmp)
     6  
     7 print(data)
     8  
     9  
    10 def user_list(request):
    11  
    12     # user_list = data[0:10]
    13     # user_list = data[10:20]
    14     try:
    15         current_page = int(request.GET.get("page"))
    16     except Exception as e:
    17         current_page = 1
    18  
    19     per_page = 10
    20  
    21     # 数据总条数
    22     total_count = len(data)
    23     # 总页码
    24     total_page, more = divmod(total_count, per_page)
    25     if more:
    26         total_page += 1
    27  
    28     # 页面最多显示多少个页码
    29     max_show = 11
    30     half_show = int((max_show-1)/2)
    31  
    32     if current_page <= half_show:
    33         show_start = 1
    34         show_end = max_show
    35     else:
    36         if current_page + half_show >= total_page:
    37             show_start = total_page - max_show
    38             show_end = total_page
    39         else:
    40             show_start = current_page - half_show
    41             show_end = current_page + half_show
    42  
    43     # 数据库中获取数据
    44     data_start = (current_page - 1) * per_page
    45     data_end = current_page * per_page
    46  
    47     user_list = data[data_start:data_end]
    48  
    49     # 生成页面上显示的页码
    50     page_html_list = []
    51     # 加首页
    52     first_li = '<li><a href="/user_list/?page=1">首页</a></li>'
    53     page_html_list.append(first_li)
    54     # 加上一页
    55     if current_page == 1:
    56         prev_li = '<li><a href="#">上一页</a></li>'
    57     else:
    58         prev_li = '<li><a href="/user_list/?page={}">上一页</a></li>'.format(current_page - 1)
    59     page_html_list.append(prev_li)
    60     for i in range(show_start, show_end+1):
    61         if i == current_page:
    62             li_tag = '<li class="active"><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
    63         else:
    64             li_tag = '<li><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
    65         page_html_list.append(li_tag)
    66  
    67     # 加下一页
    68     if current_page == total_page:
    69         next_li = '<li><a href="#">下一页</a></li>'
    70     else:
    71         next_li = '<li><a href="/user_list/?page={}">下一页</a></li>'.format(current_page+1)
    72     page_html_list.append(next_li)
    73  
    74     # 加尾页
    75     page_end_li = '<li><a href="/user_list/?page={}">尾页</a></li>'.format(total_page)
    76     page_html_list.append(page_end_li)
    77  
    78     page_html = "".join(page_html_list)
    79  
    80     return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
    View Code

封装版:

  • 优点:易维护、可拓展性强
  • 缺点:逻辑相对复杂
     1 """
     2 自定义分页组件
     3 """
     4 class Pagination(object):
     5  
     6     def __init__(self, data_num, current_page, url_prefix, per_page=10,  max_show=11):
     7         """
     8         进行初始化.
     9         :param data_num: 数据总数
    10         :param current_page: 当前页
    11         :param url_prefix: 生成的页码的链接前缀
    12         :param per_page: 每页显示多少条数据
    13         :param max_show: 页面最多显示多少个页码
    14         """
    15         self.data_num = data_num
    16         self.per_page = per_page
    17         self.max_show = max_show
    18         self.url_prefix = url_prefix
    19  
    20         # 把页码数算出来
    21         self.page_num, more = divmod(data_num, per_page)
    22         if more:
    23             self.page_num += 1
    24  
    25         try:
    26             self.current_page = int(current_page)
    27         except Exception as e:
    28             self.current_page = 1
    29             # 如果URL传过来的页码数是负数
    30         if self.current_page <= 0:
    31             self.current_page = 1
    32             # 如果URL传过来的页码数超过了最大页码数
    33         elif self.current_page > self.page_num:
    34             self.current_page = self.page_num  # 默认展示最后一页
    35  
    36         # 页码数的一半 算出来
    37         self.half_show = max_show // 2
    38  
    39         # 页码最左边显示多少
    40         if self.current_page - self.half_show <= 1:
    41             self.page_start = 1
    42             self.page_end = self.max_show
    43         elif self.current_page + self.half_show >= self.page_num:  # 如果右边越界
    44             self.page_end = self.page_num
    45             self.page_start = self.page_num - self.max_show
    46         else:
    47             self.page_start = self.current_page - self.half_show
    48             # 页码最右边显示
    49             self.page_end = self.current_page + self.half_show
    50  
    51         if self.page_num < self.page_end:
    52             self.page_end = self.page_num  # 如果总页面小于结束页面,那么结束页面即为总页码
    53  
    54     @property
    55     def start(self):
    56         # 数据从哪儿开始切
    57         return (self.current_page - 1) * self.per_page
    58  
    59     @property
    60     def end(self):
    61         # 数据切片切到哪儿
    62         return self.current_page * self.per_page
    63  
    64     def page_html(self):
    65         # 生成页码
    66         l = []
    67         # 加一个首页
    68         l.append('<li><a href="{}?page=1">首页</a></li>'.format(self.url_prefix))
    69         # 加一个上一页
    70         if self.current_page == 1:
    71             l.append('<li class="disabled" ><a href="#">«</a></li>'.format(self.current_page))
    72         else:
    73             l.append('<li><a href="{}?page={}">«</a></li>'.format(self.url_prefix, self.current_page - 1))
    74  
    75  
    76         for i in range(self.page_start, self.page_end + 1):
    77  
    78             if i == self.current_page:
    79                 tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
    80             else:
    81                 tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
    82             l.append(tmp)
    83  
    84         # 加一个下一页
    85         if self.current_page == self.page_num:
    86             l.append('<li class="disabled"><a href="#">»</a></li>'.format(self.current_page))
    87         else:
    88             l.append('<li><a href="{}?page={}">»</a></li>'.format(self.url_prefix, self.current_page + 1))
    89         # 加一个尾页
    90         l.append('<li><a href="{}?page={}">尾页</a></li>'.format(self.url_prefix, self.page_num))
    91         return "".join(l)
    View Code

     

 封装版使用步骤:

  1. 将上面的一段代码复制到自定义的模块(pt文件)中
  2. 导入自定义模块
  3. 在views系统的函数里写入以下代码
    def user_list(request):
        # 实例化一个分页类的对象
        obj = Pagination(blogs.count(),page,'blogs.html')
        # 根据传入的总博客数、页码获取当页需要展示的博客
        blog_list = blogs[obj.start:obj.end]
        # 根据传入的博客数及页码获取生成分页的html格式的页码列表
        page_html = pager.page_html()
        #返回指定页面
        return render(request, "blog_list.html", {"blog_list": blog_list, "page_html": page_html})
    View Code
  4. 在需要生成页面的html页面写入以下代码
    <div class="topicListFooter fenye">
         <ul class="pagination">
             {{ page_html|safe }}
          </ul>
     </div>
    View Code

    注:示例中用的是bootstrap分页样式

Django中的内置分页(不能展示页码列表)

 1 from django.shortcuts import render
 2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 3  
 4 L = []
 5 for i in range(999):
 6     L.append(i)
 7  
 8 def index(request):
 9     current_page = request.GET.get('p')
10  
11     paginator = Paginator(L, 10)
12     # per_page: 每页显示条目数量
13     # count:    数据总个数
14     # num_pages:总页数
15     # page_range:总页数的索引范围,如: (1,10),(1,200)
16     # page:     page对象
17     try:
18         posts = paginator.page(current_page)
19         # has_next              是否有下一页
20         # next_page_number      下一页页码
21         # has_previous          是否有上一页
22         # previous_page_number  上一页页码
23         # object_list           分页之后的数据列表
24         # number                当前页
25         # paginator             paginator对象
26     except PageNotAnInteger:
27         posts = paginator.page(1)
28     except EmptyPage:
29         posts = paginator.page(paginator.num_pages)
30     return render(request, 'index.html', {'posts': posts})
内置分页view部分
 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8 <ul>
 9     {% for item in posts %}
10         <li>{{ item }}</li>
11     {% endfor %}
12 </ul>
13  
14 <div class="pagination">
15       <span class="step-links">
16         {% if posts.has_previous %}
17             <a href="?p={{ posts.previous_page_number }}">Previous</a>
18         {% endif %}
19           <span class="current">
20             Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
21           </span>
22           {% if posts.has_next %}
23               <a href="?p={{ posts.next_page_number }}">Next</a>
24           {% endif %}
25       </span>
26  
27 </div>
28 </body>
29 </html>
内置分页HTML部分

转载于:https://www.cnblogs.com/lbzbky/articles/10945068.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值