单爆手

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

分页初版:

一.建项目并生成500条数据的出版社

(1)建一项目:

  

 

(2) models.py中:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=12)
    addr = models.CharField(max_length=255)

python manage.py makemigrations

python manage.py migrate

(3)piliang.py中:---python中用文件生成批量数据

  我想在数据库中创建500条数据/500个出版社?--怎么批量创建

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'about_page.settings')

    import django
    django.setup()

    from app01.models import Publisher
    # 先创建500个Publisher对象
    obj_list = (Publisher(name='小三{}'.format(i),addr='小四{}'.format(i)) for i in range(500))
    #bulk_create--一次创建完一次提交
    Publisher.objects.bulk_create(obj_list)

  右键运行piliang.py文件--->data source:sqlite--->测试并下载,最后如下图有表中数据了

  

 

 

(4)urls.py:

from django.contrib import admin
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publisher_list/$', views.publisher_list),
]

(5)views.py:

  查找到所有的数据。

from django.shortcuts import render
from app01.models import Publisher

def publisher_list(request):
    data = Publisher.objects.all()
    return render(request,'publisher_list.html',{'publisher_list':data})

(6)publisher_list.html:

  .复制bootstrap分页样式。

  .从bootcdn中复制3.3.7版本.

  .搭一珊格系统.

     

 

   .写一表格:bootstrap中复制带边框的表格。

    

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h1>出版社列表</h1>
            <div class="bs-example" data-example-id="bordered-table">
                <table class="table table-bordered table-strip">
                    <thead>
                    <tr>
                        <th>#</th>
                        <th>男生</th>
                        <th>女生</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for publisher in publisher_list %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ publisher.name }}</td>
                            <td>{{ publisher.addr }}</td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

</body>
</html>

 

   .如下图中修改端口为8010

  

 

   .启动项目,效果如下图有很多多数据,不方便查看:

  

 

 

二.分页初识

  想实现url地址栏中输入?page=1则为第一页,?page=n则为第n页的分页效果。

分页(Python基础)
        
        每页显示10条
        每页显示per_page条
当前页码:     切片的起始位置: 第
1页     0 - 10 第2     11 - 20 第3页     20 - 30 ... n      10*(n-1) - n * 10 总条: 每页条: 几页: 10 10 1 11 10 2 100 10 10
     n   m n/m

 

(1)views.py中:

from django.shortcuts import render
from app01.models import Publisher


def publisher_list(request):
    current_page = int(request.GET.get('page',1))#拿到当前页码,如果取不到则返回默认值第1页
    per_page = 10 #每页为10条数据
    start = 10*(current_page-1)   #切片起始位置
    end = current_page * per_page    #切片结尾位置
    data = Publisher.objects.all()[start:end] #从所有数据中切片只取切出的条数数据
    return render(request,'publisher_list.html',{'publisher_list':data})

最终效果如下:

 

  从bootstrap中复制分页组件----便于数据查看,直接点击分页即可跳转而不用在url地址栏中输入。

  在publisher_list.html中:在tabel表格标签后建一div标签并把分页代码复制在此div标签中即可。效果如下:

 三.分页初版

  上图效果中点击分页栏还不能实现跳转。且url的?page值只能接收整型,那我想要的是输入的不是整数那默认跳到第1页。且当你访问的页超过最后页的页码那我就默认显示最后一基页。

 

1.views.py中:  url的?page值只能接收整型,那我想要的是输入的不是整数那默认跳到第1页,效果如下图:

from django.shortcuts import render
from app01.models import Publisher

def publisher_list(request):
    try:
        current_page = int(request.GET.get('page',1))#拿到当前页码,如果取不到则返回默认值第1页
    except Exception as e:
        current_page = 1
    per_page = 10 #每页为10条数据
    start = 10*(current_page-1)   #切片起始位置
    end = current_page * per_page    #切片结尾位置
    data = Publisher.objects.all()[start:end] #从所有数据中切片只取切出的条数数据
    return render(request,'publisher_list.html',{'publisher_list':data})

 

url的?page值只能接收整型,那我想要的是输入的不是整数那默认跳到第1页,效果如下图:

 

 

 2.当你访问的页超过最后页的页码那我就默认显示最后一基页

  总共有多少条数据?    每页显示10条数据。总共需要多少页?

views.py中:

 

from django.shortcuts import render
from app01.models import Publisher

def publisher_list(request):
    try:
        current_page = int(request.GET.get('page',1))#拿到当前页码,如果取不到则返回默认值第1页
    except Exception as e:
        current_page = 1
    per_page = 10 #每页为10条数据
    query_set = Publisher.objects.all()
    total_count = query_set.count()  #总共多少条数据
    #计算需要多少页
    total_page, more = divmod(total_count, per_page)  #more是余数
    if more:#有值
        total_page += 1  #总页码数
    #如果访问的页码数超过总页码数默认显示最后一页
    if current_page > total_page:
        current_page = total_page
    start = 10*(current_page-1)   #切片起始位置
    end = current_page * per_page    #切片结尾位置
    data = query_set[start:end] #从所有数据中切片只取切出的条数数据
    return render(request,'publisher_list.html',{'publisher_list':data})

效果如下:

 

 3.点分页栏的页码时能显示对应页面.

  (1)publisher_list.html中分页栏页码都是a标签,所以相当于第二图中访问某页就是?page=*

  

 

  改成如这样后,在页面点分页栏页码会跳到对应页上了。

 

 

  但这就有个问题:有500页那要写500个a标签?--所以这里不能写死,写个for循环--但html页面中不能写for i in range循环,所以我在后端生成这段a标签的代码,最后保存在一变量返回给前端

把这段代码拿到后端生成:

                    <nav aria-label="Page navigation">
                        <ul class="pagination">
                            <li><a href="/publisher_list/?page=1">1</a></li>
                            <li><a href="/publisher_list/?page=2">2</a></li>
                            <li><a href="/publisher_list/?page=3">3</a></li>
                            <li><a href="/publisher_list/?page=4">4</a></li>
                            <li><a href="/publisher_list/?page=5">5</a></li>
                        </ul>
                    </nav>

最后publisher_list.html中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h1>出版社列表</h1>
            <div class="bs-example" data-example-id="bordered-table">
                <table class="table table-bordered table-strip">
                    <thead>
                    <tr>
                        <th>#</th>
                        <th>男生</th>
                        <th>女生</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for publisher in publisher_list %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ publisher.name }}</td>
                            <td>{{ publisher.addr }}</td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
                <div>
                    {{ page_html|safe }}
                </div>
            </div>
        </div>
    </div>
</div>
<form action="" method="get">
    <input type="number" name="page">
    <input type="submit" name="跳转">
</form>
</body>
</html>

 

(2)views.py中:

   把分页代码一次返回,在后端相当于用字符串拼接成html代码。

  高亮显示当前页码。

  问题:页码有出现左边有负数和零(越界)和右边越界。

  问题:总页码数小于最大要显示的页码数。

  添加首页。

  添加尾页。

  添加上一页。

  添加下一页。

  跳转框。(publisher_list.html中加一form表单中两input框即可)

 

from django.shortcuts import render
from app01.models import Publisher
# Create your views here.


def publisher_list(request):
    query_set = Publisher.objects.all()
    # 当前页码
    try:
        current_page = int(request.GET.get('page', 1))
    except Exception as e:
        current_page = 1
    # 页码必须是大于0的数
    if current_page < 1:
        current_page = 1
    # 每一页显示10条数据
    per_page = 10

    # 问:总共需要多少页
    # 1. 总共有多少条数据
    total_count = query_set.count()  # SQL语句的效率高
    # 2. 计算需要多少页
    total_page, more = divmod(total_count, per_page)
    if more:
        total_page += 1

    # 如果访问的页码数超过了总页码数,默认展示最后一页
    # if current_page > total_page:
    #     current_page = total_page
    current_page = total_page if current_page > total_page else current_page
    # 数据切片的开始位置
    start = per_page * (current_page - 1)
    # 数据切片的结束为止
    end = current_page * per_page
    # 获取当前页面的数据
    data = query_set[start:end]
    # 页面最多显示的页码数
    show_page = 9
    # 最多显示页码的一半
    half_show_page = show_page // 2



    # 页面显示页码的开始
    # 如果总页码数小于最大要显示的页码数
    if total_page < show_page:
        show_page_start = 1
        show_page_end = total_page
    # 左边越界
    elif current_page - half_show_page < 1:
        show_page_start = 1
        show_page_end = show_page
    # 右边越界
    elif current_page + half_show_page > total_page:
        show_page_end = total_page
        show_page_start = total_page - show_page + 1
    else:
        show_page_start = current_page - half_show_page
        # 页面显示页码的结束
        show_page_end = current_page + half_show_page


    # 生成分页的HTML代码
    page_list = []  #空列表,把下面的这些放里边
    # 添加分页代码的前缀
    page_list.append('<nav aria-label="Page navigation"><ul class="pagination">')
    # 添加首页
    page_list.append('<li><a href="/publisher_list/?page=1">首页</a></li>')
    # 添加上一页
    if current_page - 1 <1:  # 已经到头啦,不让点上一页啦
        page_list.append('<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>')
    else:
        page_list.append('<li><a href="/publisher_list/?page={}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(current_page-1))
    for i in range(show_page_start, show_page_end+1):
        if i == current_page:#当前页码高亮active
            s = '<li class="active"><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i)
        else:
            s = '<li><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i)
        page_list.append(s)
    # 添加下一页
    if current_page + 1 > total_page:#disabled不让点
        page_list.append('<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>')
    else:
        page_list.append('<li><a href="/publisher_list/?page={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(current_page+1))
    # 添加尾页
    page_list.append('<li><a href="/publisher_list/?page={}">尾页</a></li>'.format(total_page))
    # 添加分页代码的后缀
    page_list.append('</ul></nav>')
    page_html = ''.join(page_list) #把列表里每一个元素拼成一大的html的字符串---把此字符串传到页面即可

    return render(request, 'publisher_list.html', {'publisher_list': data, 'page_html':page_html})

最后效果如下:这样分页器就写完了。

 四.封装分页代码和添加url_prefix(a标签的url前缀)

  把上述分页器代码单独写到一个类里(封装),这样就可以套用在任何项目中,直接使用分页器效果。

  在项目下新建一个utils包,

(1)新建utils/mypage.py:

"""
自定义分页组件
可以返回分页的数据和分页的HTML代码
"""
from django.http import QueryDict

class Pagination(object):

    def __init__(self, current_page, total_count, url_prefix, query_dict=QueryDict(mutable=True), per_page=10, show_page=9):
        """
        初始化分分页器,把以下这些值数据封装到此对象中--即这些值需要你调用时在视图函数中要传给分页器
        :param url_prefix: a标签的URL前缀
        :param query_dict: 空的QueryDict()对象,并且是可修改的
        :param current_page: 当前页码数
        :param total_count: 数据总数
        :param per_page: 每一页显示多少数据, 默认值是10
        :param show_page: 页面显示的页码数, 默认值是9
        """
        # 0.分页的URL前缀
        self.url_prefix = url_prefix #a标签的url前缀
        self.query_dict = query_dict
        # 1. 每一页显示10条数据
        assert per_page > 0  # 每页显示多少的数据必须是一个大于0的数
        self.per_page = per_page
        # 2. 计算需要多少页
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        self.total_page = total_page
        # 3. 当前页码
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1
        current_page = total_page if current_page > total_page else current_page
        # 页码必须是大于0的数
        if current_page < 1:
            current_page = 1
        self.current_page = current_page
        # 4. 页面最多显示的页码数
        self.show_page = show_page
        # 5. 最多显示页码的一半
        self.half_show_page = self.show_page // 2

    @property
    def start(self):
        # 数据切片的开始位置
        return self.per_page * (self.current_page - 1)

    @property
    def end(self):
        # 数据切片的结束为止
        return self.current_page * self.per_page

    # 定义一个返回HTML代码的方法
    def page_html(self):
        if self.total_page == 0:
            return ''
        # 如果总页码数小于最大要显示的页码数
        if self.total_page < self.show_page:
            show_page_start = 1
            show_page_end = self.total_page
        # 左边越界
        elif self.current_page - self.half_show_page < 1:
            show_page_start = 1
            show_page_end = self.show_page
        # 右边越界
        elif self.current_page + self.half_show_page > self.total_page:
            show_page_end = self.total_page
            show_page_start = self.total_page - self.show_page + 1
        else:
            show_page_start = self.current_page - self.half_show_page
            # 页面显示页码的结束
            show_page_end = self.current_page + self.half_show_page
        # 生成分页的HTML代码
        page_list = []
        # 添加分页代码的前缀
        page_list.append('<nav aria-label="Page navigation"><ul class="pagination">')
        # 添加首页
        self.query_dict['page'] = 1
        page_list.append('<li><a href="{}?{}">首页</a></li>'.format(self.url_prefix, self.query_dict.urlencode()))
        # 添加上一
        if self.current_page - 1 < 1:  # 已经到头啦,不让点上一页啦
            page_list.append(
                '<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>')
        else:
            self.query_dict['page'] = self.current_page - 1
            page_list.append(
                '<li><a href="{}?{}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(
                    self.url_prefix,
                    self.query_dict.urlencode())
            )
        for i in range(show_page_start, show_page_end + 1):
            self.query_dict['page'] = i
            if i == self.current_page:
                s = '<li class="active"><a href="{1}?{2}">{0}</a></li>'.format(i, self.url_prefix, self.query_dict.urlencode())
            else:
                s = '<li><a href="{1}?{2}">{0}</a></li>'.format(i, self.url_prefix, self.query_dict.urlencode())
            page_list.append(s)
        # 添加下一页
        if self.current_page + 1 > self.total_page:
            page_list.append(
                '<li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>')
        else:
            self.query_dict['page'] = self.current_page + 1
            page_list.append(
                '<li><a href="{}?{}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(
                    self.url_prefix,
                    self.query_dict.urlencode())
            )
        # 添加尾页
        self.query_dict['page'] = self.total_page
        page_list.append('<li><a href="{}?{}">尾页</a></li>'.format(self.url_prefix, self.query_dict.urlencode()))
        # 添加分页代码的后缀
        page_list.append('</ul></nav>')
        page_html = ''.join(page_list)
        return page_html

(2)views.py中:使用分页器

from django.shortcuts import render
from app01.models import Publisher
from utils.mypage import Pagination #导入自定的分页器模块
# Create your views here.


def publisher_list(request):
    url_prefix = request.path_info  #拿到当前页的url前缀
    current_page = request.GET.get('page', 1)
    query_set = Publisher.objects.all()
    total_count = query_set.count()  # SQL语句的效率高
    # 生成一个分页实例
    page_obj = Pagination(current_page, query_set.count(), url_prefix,show_page=5)
    # 取到当前页面的数据
    data = query_set[page_obj.start:page_obj.end]
    # 取到分页的HTML代码
    page_html = page_obj.page_html()
    return render(request, 'publisher_list.html', {'publisher_list': data, 'page_html':page_html})

 (3)在别的项目中如何调用我封装的这个分页器:          

 如在我的crm项目中导入分页器使用在客户列表页面:

  a.把mypage.py拷贝到crm项目下的utils包中:

  b.项目视图函数中导入分页器:from utils.mypage import Pagination

  c.在views.py中的客户列表页面customer_list方法中作处理:

from utils.mypage import Pagination


@login_required()
def customer_list(request):
    url_prefix = request.path_info #获取当前url前缀
    current_page = request.GET.get('page', 1) #获取当前页码
    query_set = Customer.objects.all()#拿到所有客户及信息
    page_obj = Pagination(current_page, query_set.count(), url_prefix, per_page=2)#页码,数据量,url前缀,每页几条--给分页器传这几个值即可
    data = query_set[page_obj.start:page_obj.end]#切片
    # 2. 在页面上展出出来
    return render(request, 'customer_list.html', {'customer_list': data, 'page_html': page_obj.page_html()})#把分页的html字符串代码传给前端

  d.在customer_list.html模版中加分页器如下:

  

 

 这样重新启动我的crm后,就有分页的效果了如下图:

 

 

3

 

4

 

posted on 2020-04-09 15:36  单爆手  阅读(178)  评论(0)    收藏  举报