欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

程序员文章站 2022-04-10 22:01:36
摘要 MTV与MVC 多对多表三种创建方式 ajax ,前后端传输数据编码格式contentType 批量插入数据和自定义分页器 MTV与MVC 多对多表三种创建方式 ajax ,前后端传输数据编码格式contentType 批量插入数据和自定义分页器 一、MVC与MTV MVC(Model Vie ......

摘要

  • mtv与mvc

  • 多对多表三种创建方式

  • ajax ,前后端传输数据编码格式contenttype

  • 批量插入数据和自定义分页器

 一、mvc与mtv

  • mvc(model view controller 模型-视图-控制器)
    是一种web架构的模式,所谓mvc就是把web应用分为模型(m),控制器(c),视图(v)三层;他们之间以一种插件似的,松耦合的方式连接在一起。

    模型负责业务对象与数据库的对象(orm),视图负责与用户的交互(页面),控制器(c)接受用户的输入调用模型和视图完成用户的请求。

    model: 代表数据存取层,
    view 代表的是系统中选择显示什么和怎么显示的部分,
    controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。
    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)
  • mtv(model templates view 模型-模板-视图)django框架就是mtv模型
    models:数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效,是一个抽象层,用来构建和操作你的web应用中的数据,模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。
    模板(templates):即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。模板层提供了设计友好的语法来展示信息给用户。使用模板方法可以动态地生成html。模板包含所需html 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。
    视图(views):业务逻辑层,该层包含存取模型及调取恰当模板的相关逻辑。用于封装负责处理用户请求及返回响应的逻辑。视图可以看作是前端与数据库的中间人,他会将前端想要的数据从数据库中读出来给前端。他也会将用户要想保存的数据写到数据库。

    django的mtv模式本质上与mvc模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,django的mtv分别代表:

           model(模型):负责业务对象与数据库的对象(orm)

           template(模版):负责如何把页面展示给用户

           view(视图):负责业务逻辑,并在适当的时候调用model和template

           此外,django还有一个url分发器,它的作用是将一个个url的页面请求分发给不同的view处理,view再调用相应的model和template
    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

 二、多对多表的创建

  • 第①种:django自带的orm自动创建的多对多表(manytomanyfield(to='...‘))
    # 多表查询示例表
    class book(models.model):
        title = models.charfield(max_length=32)
        price = models.decimalfield(max_digits=8, decimal_places=2)
        publish_date = models.datefield(auto_now_add=true)
        # 外键关系
        # 一对多:(外键)
        publish = models.foreignkey(to='publish')
        # 多对多:
        author = models.manytomanyfield(to='author')   # 这是一个虚拟字段, 信号字段
    
    class author(models.model):
        name = models.charfield(max_length=32)
        age = models.integerfield()

    很显然,django自动创建的多对多表,支持双下划线查询语法。

  • 第②种纯手动创建多对多表:
    # 多对多表创建实例:
    
    class mybook(models.model):
        title = models.charfield(max_length=32)
        price = models.decimalfield(max_digits=8, decimal_places=2)
        publish_date = models.datefield(auto_now_add=true)
    
    class myauthor(models.model):
        name = models.charfield(max_length=32)
        age = models.integerfield()
    
    class mybook2myauthor(models.model):
        # 这里的book和author不要加_id,因为会django识别forenginkey,并给其自动加上_id
        book = models.foreignkey(to='mybook')
        author = models.foreignkey(to='myauthor')
        #纯手动创建多对多,可以在该关联表中加入自己需要的字段
        info = models.charfield(max_length=32)
    # models中表关系映射创建完了,记得一定要对django数据库进行迁移(保存)操作
    
    数据库迁移方法一:
    cmd命令:
    python3 manage.py makemigrations
    migrate
    
    数据库迁移方法二:
    pycharm中菜单栏tools下有个run manage.py task...打开输入如下命令
    makemigrations
    migrate

    数据库迁移完之后我们看看创建的三张表(navicat查看):
    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)
    先创建一些数据:
    提示一下:为了直接在django页面中运行我们的测试表查询代码,快速显示结果,我们需要对django进行配置一下:配置方法见我另一篇博客文中单表查询处:

    # 测试表查询py文件内:
    import os if __name__ == "__main__": os.environ.setdefault("django_settings_module", "created_by_pycharm.settings") import django django.setup() from app01 import models models.myauthor.objects.create(name='吴承恩', age=100) models.myauthor.objects.create(name='吴彦祖', age=30) models.myauthor.objects.create(name='刘德华', age=45) models.myauthor.objects.create(name='刘志鹏', age=18) models.myauthor.objects.create(name='曹雪芹', age=120) res1 = models.mybook.objects.create(title='西游记', price=66.6) res2 = models.mybook.objects.create(title='东游记', price=99.9) res3 = models.mybook.objects.create(title='南游记', price=88.8) res4 = models.mybook.objects.create(title='北游记', price=68.6) # 由于多对多这张表是我们自己创建的,所以在数据库中是真实存在的,它关联着myautho和 # mybook这2张表,所以添加表关系的时候在任何一个mybook或者是myauthor # 表对象点mybook2myauthor_set.add()的方法是行不通的: # models.mybook.objects.filter(pk=1).first().mybook2myauthor.add(5) # 错误提示:attributeerror: 'mybook' object has no attribute 'mybook2myauthor' # 因为外键建立在多对多那张关联表中,所以要添加关系需要在这张表中动手脚 models.mybook2myauthor.objects.create(book_id=1, author_id=1) models.mybook2myauthor.objects.create(book_id=1, author_id=2) models.mybook2myauthor.objects.create(book_id=2, author_id=2) models.mybook2myauthor.objects.create(book_id=2, author_id=3) models.mybook2myauthor.objects.create(book_id=3, author_id=4) models.mybook2myauthor.objects.create(book_id=4, author_id=5)

    下面来验证手动创建的多对多表可否使用django的orm表查询和基于双下划线的反向查询:

    # res1 = models.mybook.objects.filter(pk=1).first().author.name
        # print(res1)  # 报错:'mybook' object has no attribute 'author'
        # res2 = models.mybook.objects.filter(pk=1).first().mybook2myauthor_set.all().info
        # print(res2)
        # res4 = models.mybook.objects.filter(pk=1).first().author_set.all().name
        # print(res4)  # 报错
        # res5 = models.mybook.objects.filter(pk=1).values('author__name')
        # print(res5)  # 报错
    
    很显然用原来的orm方法貌似不行,同时用下划线试了也不行

    很显然,外键的建立位置变了,肯定这样查不行,外键全部在mybook2myauthor这张表中,所以要想从一张表查到另外一张表,必须要先经过mybook2myauthor这张表。
    至于如何查询,本文不作深入探讨,咱们继续下一种方法:半自动化建立多对多表。

  • 半自动创建多对多表(该方法的可拓展性高,并且符合orm查询规则,在项目中使用频率也最高,需要重点掌握
    class books(models.model):
        title = models.charfield(max_length=32)
        price = models.decimalfield(max_digits=8, decimal_places=2)
        publish_date = models.datefield(auto_now_add=true)
        author = models.manytomanyfield(to='authors', through='books2authors', through_fields=('book', 'author'))
    
    class authors(models.model):
        name = models.charfield(max_length=32)
        age = models.integerfield()
    
    class books2authors(models.model):
    
        book = models.foreignkey(to='books')
        author = models.foreignkey(to='authors')
        #纯手动创建多对多,可以在该关联表中加入自己需要的字段
        info = models.charfield(max_length=32)

    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

    # 创建一些数据,添加表关系
        models.authors.objects.create(name='吴承恩', age=100)
        models.authors.objects.create(name='吴彦祖', age=30)
        models.authors.objects.create(name='刘德华', age=45)
        models.authors.objects.create(name='刘志鹏', age=18)
        models.authors.objects.create(name='曹雪芹', age=120)
        res1 = models.books.objects.create(title='西游记', price=66.6)
        res2 = models.books.objects.create(title='东游记', price=99.9)
        res3 = models.books.objects.create(title='南游记', price=88.8)
        res4 = models.books.objects.create(title='北游记', price=68.6)
        models.books2authors.objects.create(book_id=1, author_id=1)
        models.books2authors.objects.create(book_id=1, author_id=2)
        models.books2authors.objects.create(book_id=2, author_id=2)
        models.books2authors.objects.create(book_id=2, author_id=3)
        models.books2authors.objects.create(book_id=3, author_id=4)
        models.books2authors.objects.create(book_id=4, author_id=5)
        # orm查询可行性
    res = models.books.objects.filter(pk=1).first().author.all().values('name') res1 = models.authors.objects.filter(pk=1).first().books_set.all().values('title') print(res) # <queryset [{'name': '吴承恩'}, {'name': '吴彦祖'}]> print(res1) # <queryset [{'title': '西游记'}]>
    # 双下划线查询可行性:
        res = models.books.objects.filter(pk=1).values_list('author__name')
        res1 = models.authors.objects.filter(pk=1).values_list('books__title')
        print(res)  # <queryset [('吴承恩',), ('吴彦祖',)]>
        print(res1)  # <queryset [('西游记',)]>

    通过上面查询结果可知这种半自动创建多对多表的方法可以使用orm查询方法也支持双下划线方法

 三、ajax,前后端传输编码格式contenttype

 

  • ①urlencoded (默认格式)
    对应数据格式:name=jason&password=666
    后端获取方式:request.post
    django会将urlencoded编码数据解析自动放到request.post中
  • ②formdata(form表单传输文件编码格式)
    注意form表单默认的传输编码格式是urlencoded(enctype="application/x-www-form-urlencoded"),如果需要传输文件,这里需要手动设置成formdata格式(enctype="multipart/form-data"),
    后端:通过request.post 继续获取普通字符串格式数据,通过request.files获取文件格式数据
  • ③json格式(ajax支持)
    什么是json:
    • son 指的是 javascript 对象表示法(javascript object notation)
    • json 是轻量级的文本数据交换格式
    • json 独立于语言 *
    • json 具有自我描述性,更易理解

    * json 使用 javascript 语法来描述数据对象,但是 json 仍然独立于语言和平台。json 解析器和 json 库支持许多不同的编程语言。
    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

    合格的json对象(json只认双引的字符串格式):

    ["one", "two", "three"]
    { "one": 1, "two": 2, "three": 3 }
    {"names": ["张三", "李四"] }
    [ { "name": "张三"}, {"name": "李四"} ] 

    不合格的json对象:

    { name: "张三", 'age': 32 }  // 属性名必须使用双引号
    [32, 64, 128, 0xfff] // 不能使用十六进制值
    { "name": "张三", "age": undefined }  // 不能使用undefined
    { "name": "张三",
      "birthday": new date('fri, 26 aug 2011 07:13:10 gmt'),
      "getname":  function() {return this.name;}  // 不能使用函数和日期对象
    }
  • 关于json在javascript中的2个方法:
    stringfy与parse方法
    javascript中关于json对象和字符串转换的两个方法:
    json.parse(): 用于将一个 json 字符串转换为 javascript 对象(json只认双引的字符串格式)
    json.parse('{"name":"howker"}');
    json.parse('{name:"stack"}') ;   // 错误
    json.parse('[18,undefined]') ;   // 错误

    json.stringify(): 用于将 javascript 值转换为 json 字符串。

    json.stringify({"name":"tonny"})
  • 补充
    json与xml的区别

    json 格式于2001年由 douglas crockford 提出,目的就是取代繁琐笨重的 xml 格式。

    json 格式有两个显著的优点:书写简单,一目了然;符合 javascript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,json迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ecmascript 5,成为标准的一部分。

    xml和json都使用结构化方法来标记数据,下面来做一个简单的比较。

    用xml表示中国部分省市数据如下:

    <?xml version="1.0" encoding="utf-8"?>
    <country>
        <name>中国</name>
        <province>
            <name>黑龙江</name>
            <cities>
                <city>哈尔滨</city>
                <city>大庆</city>
            </cities>
        </province>
        <province>
            <name>广东</name>
            <cities>
                <city>广州</city>
                <city>深圳</city>
                <city>珠海</city>
            </cities>
        </province>
        <province>
            <name>*</name>
            <cities>
                <city>台北</city>
                <city>*</city>
            </cities>
        </province>
        <province>
            <name>*</name>
            <cities>
                <city>乌鲁木齐</city>
            </cities>
        </province>
    </country>

    用json表示如下:

    {
        "name": "中国",
        "province": [{
            "name": "黑龙江",
            "cities": {
                "city": ["哈尔滨", "大庆"]
            }
        }, {
            "name": "广东",
            "cities": {
                "city": ["广州", "深圳", "珠海"]
            }
        }, {
            "name": "*",
            "cities": {
                "city": ["台北", "*"]
            }
        }, {
            "name": "*",
            "cities": {
                "city": ["乌鲁木齐"]
            }
        }]
    }

    由上面的两端代码可以看出,json 简单的语法格式和清晰的层次结构明显要比 xml 容易阅读,并且在数据交换方面,由于 json 所使用的字符要比 xml 少得多,可以大大得节约传输数据所占用得带宽。

  • ajax简介

    ajaxasynchronous javascript and xml)翻译成中文就是异步的javascriptxml”。即使用javascript语言与服务器进行异步交互,传输的数据为xml(当然,传输的数据不只是xml)。

    ajax 不是新的编程语言,而是一种使用现有标准的新方法。

    ajax 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

    ajax 不需要任何浏览器插件,但需要用户允许javascript在浏览器上执行。

    • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
    • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
  • ajax的基本使用方法:
    # 前端向后端请求方式:1 浏览器手动输入网址(get请求),2 a标签的href属性(get请求),form表单(get/post请求,默认为get)
    # ajax特点:异步提交、局部刷新
    # 基本使用语法:
      提交url   (url:’...‘)
      提交方式  (type: 'post')
      提交数据  (data:{'''})
      提交后通过回调函数得到的返回结果  (sucess:function(data){...})
    # 基本使用示例:(ajax的默认传输数据的格式是urlencoded
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>图书管理系统</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="/static/layui/css/layui.css">
        <script src="/static/layui/layui.js"></script>
        <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>
    
    </head>
    <body>
    <button class="btn btn-success" id="b1">ajax测试</button>
    <script>
        {#绑定按钮点击触发ajax提交数据#}
        $('#b1').on('click', function () {
            $.ajax({    {#固定语法格式#}
                url: '',  {#不写默认朝当前页面发请求#}
                type: 'post',   {#请求方式#}
                data : {'name': 'sgt', 'pwd': '123'},    {#发送的请求数据#}
                {#这里的data就是回调函数success获取到的后端响应返回的数据#}
                success:function (data) {
                    swal({
                        title: 'ajax',
                        text: '模拟这里显示了返回的数据',
                        icon: 'success',
                        button: 'ok',
                        })
                }
            })
        })
    </script>
    </body>
    </html>

     我们知道ajax默认的传输数据格式是urlencoded,前面我们说过,ajax可以用json作为数据格式传输
    现在强调一点:前后端传输数据必须要求数据是什么格式就应该用对应的传输格式,一一对应去传输,否则django解析数据出问题,以至于我们在前后端拿不到想要的数据。

    所以:
    第一:我们需要在ajax发送请求代码中指定发送数据格式:
    contenttype: 'application/json',
    第二:后端获取json格式数据不再是request.post,而是通过request.body(得到的是一个bytes类型的json格式数据),所以再处理一下:
    res = json.loads(request.body.decode('utf-8')),这就得到前端ajax发送过来的json格式数据
  • ajax传文件
    前端:
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>图书管理系统</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="/static/layui/css/layui.css">
        <script src="/static/layui/layui.js"></script>
        <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>
    
    </head>
    <body>
        <input type="file" id="f1">
        <br>
        <button id="s1" class="btn btn-default">提交</button>
    <script>
        //需要知道,ajax无法自己传文件,需要借助于内置对象formdata
        $('#s1').on('click', function () {
            //ajax借助formdata内置对象传文件
            let formdata = new formdata();
            //formdata不仅能传文件,也能传普通键值
            formdata.append('name', 'sgt');  <!--添加普通键值-->
            //获取input框存放文件
            file_data = $('#f1')[0].files[0];
            //$('#f1')[0]是将jquery对象转换成js对象,然后通过js对象点files来获取到文件对象,然后去索引0才能拿到文件对象
            formdata.append('myfile', file_data);
            //使用ajax发送文件
            $.ajax({
                url: '',
                type: 'post',
                data: formdata,       <!--传输数据为formdata-->
                processdata: false,   <!--告诉浏览器不要处理数据-->
                contenttype: false,   <!--不要用任何编码,就用我formdata自带的格式,因为django能自动识别formdata-->
                //回调函数获取提交后后端返回的数据
                success:function (data) {
                    swal({     <!--用sweetalert显示结果-->
                        title: '传输文件',
                        text: data,
                        icon: 'success',
                        button: 'ok',
                    })
                }
            })
        })
    </script>
    </body>
    </html>

    后端

    def ttt(request):
        if request.method == 'post':
            print(request.post)  # 拿到ajax传来的formdata普通键值数据
            print(request.files)  # 拿到ajax传来的formdata文件
            return httpresponse('我从后端来,文件[%s]已收到' % request.files.get('myfile'))
        return render(request, 'ttt.html')

    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

  • 通过ajax监控input框,发送数据到后端判断输入用户名是否存在与数据库user表中
    前端:
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>图书管理系统</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="/static/layui/css/layui.css">
        <script src="/static/layui/layui.js"></script>
        <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-sm-4 col-sm-offset-4">
                用户名: <input type="text" class="user form-control">
                <span class="hide" style="color: red">用户已存在</span>
            </div>
        </div>
    </div>
    <p></p>
    <script>
        //input事件来实时监控input框输入的数据,如果用change,则在input框失去焦点时候触发
        $('.user').on('input',function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'username': $(this).val()},
                success:function (data) {
                    {#res = json.parse(data);#}
                    if (data['flag']){
                        $('div>span').removeclass('hide')}
                    else {
                        $('div>span').addclass('hide')
                        }
                    }
            })
        })
    
    </script>
    </body> </html>

     后端:

    def ttt(request):
        if request.method == 'post':
            res = {'flag': false}
            # 获取到ajax发送过来的username
            username = request.post.get('username')
            # 通过username进行数据库查询
            user_obj = models.user.objects.filter(name=username).first()
            # 判断用户名是否存在与数据库中
            if user_obj:
                res['flag'] = true
            return jsonresponse(res)
        return render(request, 'ttt.html')

     结果演示:

    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

    总结一下:
    form表单与ajax的异同点:
    1、form表单不支持异步提交,局部刷新
    2、form表单不支持传输json格式数据
    3、form表单与ajax默认传输数据编码格式都是urlencoded

四、批量插入数据与自定义分页器

  • bulk_create批量插入数据
    当我们使用orm来一次性新增很多表记录的时候,等待结果的时间会非常的慢,如果一次性需要批量插入很多数据的时候就需要使用bulk_create来批量插入数据
    import random
    
    user_list = ['用户[{}]'.format(i) for i in range(100)]
    data = []
    for j in user_list:
        data.append(models.myuser(name=j, password='123', gender=str(random.choice([1, 2, 3]))))
    models.myuser.objects.bulk_create(data)
  • 自定义分页器
    自定义分页器的实现过程:
    每一页显示多少条数据
    第n页显示的数据在全部条数据中的开始和结尾索引位置,然后通过这个索引位置进行切片处理,取出这一页的所有数据的对象列表,在后端进行for循环渲染成html代码后通过模板语法发送到前端,通过safe方法实现前端的动态渲染,达到点击对应页数标签进行页面切换的效果显示
    tip:需要用到的相关知识与方法:列表的切片[0:10],a标签的href="?page=6"(路径前加上一个?,表示当前路径自动补全),divmod()方法(div(100,9)>>(11,1) 除取余),models.user.objects.all().count()计算记录总条数
    分页器的实现如果自己写下来还是比较麻烦的,所以我们直接使用已经封装好的分页器就行了,下面介绍一个分页器模板,只需几步操作就能使用:
    class pagination(object):
        def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param pager_count:  最多显示的页码个数
            
            用法:
            queryset = model.objects.all()
            page_obj = pagination(current_page,all_count)
            page_data = queryset[page_obj.start:page_obj.end]
            获取数据用page_data而不再使用原始的queryset
            获取前端分页样式用page_obj.page_html
            """
            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_num = per_page_num
    
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            # 添加前面的nav和ul标签
            page_html_list.append('''
                        <nav aria-label='page navigation>'
                        <ul class='pagination'>
                    ''')
            first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                if i == self.current_page:
                    temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
                else:
                    temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
            page_html_list.append(next_page)
    
            last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
            page_html_list.append(last_page)
            # 尾部添加标签
            page_html_list.append('''
                                               </nav>
                                               </ul>
                                           ''')
            return ''.join(page_html_list)
    下面通过上面的批量插入数据和分页器模板来实现分页效果:
    先批量插入数据:
    l = [models.user(name='这是第%s记录' % i) for i in range(1000)]
    models.user.objects.bulk_create(l)

     

    然后操作分页器的实现:
    ①:app01程序文件夹下面新建文件夹utils>>>>>>在utils下面新建.my_page.py文件,名字随便取
    ②:my_page.py文件内:将刚才的模板代码粘贴进去
    class pagination(object):
        def __init__(self, current_page, all_count, per_page_num=20, pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param pager_count:  最多显示的页码个数
    
            用法:
            queryset = model.objects.all()
            page_obj = pagination(current_page,all_count)
            page_data = queryset[page_obj.start:page_obj.end]
            获取数据用page_data而不再使用原始的queryset
            获取前端分页样式用page_obj.page_html
            """
            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_num = per_page_num
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            # 添加前面的nav和ul标签
            page_html_list.append('''
                        <nav aria-label='page navigation>'
                        <ul class='pagination'>
                    ''')
            first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                if i == self.current_page:
                    temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
                else:
                    temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
            page_html_list.append(next_page)
    
            last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
            page_html_list.append(last_page)
            # 尾部添加标签
            page_html_list.append('''
                                               </nav>
                                               </ul>
                                           ''')
            return ''.join(page_html_list)

    ③:视图文件views.py中:

    def ttt(request):
    
        user_list = models.user.objects.all()
        all_count = user_list.count()
        current_page = request.get.get('page', 1)
        page_obj = my_page.pagination(current_page=current_page, all_count=all_count)
        page_queryset = user_list[page_obj.start:page_obj.end]
        return render(request, 'ttt.html', locals())

    ④:html文件中:

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>图书管理系统</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="/static/layui/css/layui.css">
        <script src="/static/layui/layui.js"></script>
        <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <table class="text-center table-bordered table table-hover table-striped">
                    <thead>
                    <tr>
                        <th>id</th>
                        <th>name</th>
                        <th>password</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for user in page_queryset %}
                        <tr>
                            <th>{{ user.pk }}</th>
                            <th>{{ user.name }}</th>
                            <th>{{ user.password }}</th>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            {{ page_obj.page_html|safe }}
            </div>
        </div>
    </div>
    
    </body>
    </html>

     

    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

    演示结果:
    2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)