zoukankan      html  css  js  c++  java
  • Django框架进阶6 多对多三种创建方式, Ajax, Content-Type前后端传输数据编码格式, Ajax发送文件数据, django内置的序列化功能, Ajax结合sweetalert实现删除二次确认, 批量插入数据, 自定义分页器, ajax结合sweetalert实现删除二次确认

    多对多三种创建方式

    1.全自动(较为常用)

        class Book(models.Model):
            title = models.CharField(max_length=32)
            authors = models.ManyToManyField(to='Author')
            # orm就会自动帮你创建第三张表
            
        class Author(models.Model):
            name = models.CharField(max_length=32)
            
        '''
        好处:第三张表自己创建
        不足之处:第三张表无法扩展额外的字段
        '''

    2.纯手动(了解)

        class Book(models.Model):
            title = models.CharField(max_length=32)
    
        class Author(models.Model):
            name = models.CharField(max_length=32)
    
        class Book2Author(models.Model):
            book = models.ForeignKey(to='Book')
            author = models.ForeignKey(to='Author')
            create_time = models.DateField(auto_now_add=True)
        
            """
            好处在于第三表可以扩展额外的字段
            不足之处:orm查询的时候会带来不便
            """            

    3.半自动(推荐)

        class Book(models.Model):
            title = models.CharField(max_length=32)
            authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author'))
    
    
        class Author(models.Model):
            name = models.CharField(max_length=32)
            books = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('author', 'book'))
    
    
        class Book2Author(models.Model):
            book = models.ForeignKey(to='Book')
            author = models.ForeignKey(to='Author')
            create_time = models.DateField(auto_now_add=True)
    
    
        """
        好处在于第三步可以扩展任意的额外字段 还可以利用orm 正反向查询
        不足之处:无法利用
            add
            set
            remove
            clear
        虽然无法使用了 但是你还可以自己直接操作第三表
        """

    Ajax(异步提交、局部刷新)

    同步与异步

    同步  任务提交之后原地等待任务的返回结果  进程表现上来说  阻塞

    异步  任务提交之后不需要原地等待返回结果  直接执行下一行代码  继承表现上来说  非阻塞任务的结果肯定是需要的  是通过异步回调机制  callback()

    与后端进行交互的方式

    1.浏览器窗口输入url回车    GET

    2.a标签href属性填写url点击     GET

    3.form表单          GET/POST

    4.Ajax            GET/POST

    Ajax并不是一门新的语言  它其实就是基于js写的一个功能模块而已

    由于原生js书写ajax较为繁琐  所以我们直接学jQuery封装好的ajax模块操作

    初识ajax

    案例:页面上有三个input框  一个按钮

    用户在前两个框中输入数字  点击按钮保证页面不刷新的情况下将数据发到后端做计算

    将计算好的结果再发给前端展示到第三个input框中

    ajax基本语法结构

    // ajax基本语法
    $.ajax({
        // 1.到底朝哪个后端提交数据
        url:'',  // 控制数据的提交路径  有三种写法 跟form表单的action属性一致
        // 2.指定当前请求方式
        type:'post',
        // 3.提交的数据
        data:{'i1':$('#i1').val(),'i2':$('#i2').val()},
        // 4.ajax是异步提交 所以需要给一个回调函数来处理返回的结果
        success:function (data) {  // data就是异步提交的返回结果
            // 将异步回调的结果通过DOM操作渲染到第三个input框中
            $('#i3').val(data)
        }
    })

    例:

    templates/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
    <button id="d1">按钮</button>
    
    <script>
        $('#d1').click(function () {
            // 获取两个框里面内容  朝后端提交异步请求
            // ajax基本语法
            $.ajax({
                // 1.到底朝那个后端提交数据
                url:'', // 控制数据的提交路径  有三种写法  跟form表单的action属性一样
                // 2.指定当前请求方式
                type:'post',
                // 3.提交的数据
                data:{'i1':$('#i1').val(),'i2':$('#i2').val()},
                // 4.ajax是异步提交  所以需要给一个回调函数来处理返回的结果
                success:function (data) {   // data就是异步提交的返回结果
                    // 将异步回调的结果通过DOM操作渲染到第三个input框中
                    $('#i3').val(data)
                }
            })
        })
    </script>
    </body>
    </html>

    app01/views.py

    from django.shortcuts import render,HttpResponse
    
    def index(request):
        if request.method == 'POST':
            i1 = request.POST.get('i1')
            i2 = request.POST.get('i2')
            # i1 和 i2 是字符串类型  需要先做类型转换
            i3 = int(i1) + int(i2)
            return HttpResponse(i3)
        return render(request,'index.html')

    content-Type前后端传输数据的编码格式

      urlencoded
      formdata
      application/json

    form表单

      默认是urlencoded编码格式传输数据

       urlencoded数据格式

          username=jason&password=123

          django后端针对该格式的数据  会自动解析并帮你打包到request.POST中

      formdata数据格式

          django后端针对符合urlencoded编码格式数据(普通键值对)还是统一解析到request.POST

          而针对formdata文件数据就会自动解析放到request.FILES

    ajax提交

      ajax默认的也是urlencoded编码格式

        前后端数据交互   编码格式与数据格式一定要一致

      application/json

        django后端针对json格式数据  并不会做任何的处理

        因为没有人拿,数据就以二进制的形式存放在request.body中

    $('#d2').on('click',function () {
        $.ajax({
                rl:'',
                type:'post',
                // 修改content-Type参数
                contentType:'application/json',
                data:JSON.stringify({'username':'jason','password':123}),  // 将数据序列化成json格式字符串
                success:function (data) {
                alert(data)
                }
           })
    })

    例:

    templates/ab_ct.html

    <button id="d2">ajax发送json格式数据</button>
    <script>
        $('#d2').on('click',function () {
            $.ajax({
                url:'',
                type:'post',
                // 修改content-Type参数
                contentType:'application/json',
                data:JSON.stringify({'username':'jason','password':123}),   // 将数据序列化成JSON格式字符串
                success:function (data) {
                    alert(data)
                }
            })
        })
    
    </script>
    View Code

    app01/views.py

    from django.shortcuts import render,HttpResponse
    import json
    
    def ab_ct(request):
        if request.method == 'POST':
            # print(request.POST)
            # print(request.FILES)
            # print(request.body)
            #自己处理json格式数据
            json_bytes = request.body
            # 先解码
            # json_str = json_bytes.decode('utf8')
    
            # 扩展 json.loads能够自动解码并序列化
            json_dict = json.loads(json_bytes)
            print(json_dict,type(json_dict))
    
        return render(request,'ab_ct.html')

    ajax中dataType属性:

    # 前端
    $.ajax({ url:
    '', # 控制后端提交路径 type:'', # 控制请求方式 data:{}, # 控制提交的数据 dataType:"JSON", # 有此句,django后端用HttpResponse返回json格式字符串,args会自动反序列化,拿到的是前端js的对象类型,而如果是用JsonResponse返回的那么args会自动返序列化成前端js的对象类型(如果此行不写,django后端用HttpResponse返回json格式字符串,args不会自动反序列化,拿到的还是json格式字符串string字符类型.如果是用JsonResponse返回,返回还是前端js的对象类型) success:function(args){ # 异步回调机制 }) # 后端 def index(request): if request.method == 'POST': back_dic = {'msg':'hahaha'} return HttpResponse(json.dumps(back_dic)) # 需要加dataType:"JSON" return JsonResponse(back_dic) # 不需要 return render(request,'index.html') # 后续在写ajax请求的时候建议你加上dataType参数

    ajax发送文件(******)

    内置对象FormData

    即发普通键值对也发文件

    <input type="file" name="myfile" id="i1">
    <button id="d3">ajax发送文件数据</button>
    <script>
         $('#d3').click(function () {
             // 1 需要先生成一个内置对象
                var myFormData = new FormData();
                // 2 传普通键值对  当普通键值对较多的时候 我们可以利用for循环来添加
                myFormData.append('username','jason');
                myFormData.append('password',123);
                // 3 传文件
                myFormData.append('myfile',$('#i1')[0].files[0]);  // 获取input框内部用户上传的文件对象
                // 发送ajax请求
                $.ajax({
                    url:'',
                    type:'post',
                    data:myFormData,
                    // 发送formdata对象需要指定两个关键性的参数
    
                    processData:false,  // 让浏览器不要对你的数据进行任何的操作
                    contentType:false,  // 不要使用任何编码格式 对象formdata自带编码格式并且django能够识别该对象
    
                    success:function (data) {
                        alert(data)
                    }
                })
            })
    </script>

    序列化

    django内置序列化组件

      接口文档 表名该大字典内都有哪些键值对

    from django.shortcuts import render,HttpResponse,redirect
    import json
    
    # Create your views here.
    from app01 import models
    from django.core import serializers
    def ab_se(request):
        user_queryset = models.Userinfo.objects.all()
        # user_list = []
        # for user_obj in user_queryset:
        #     user_list.append({
        #         'username':user_obj.username,
        #         'password':user_obj.password,
        #         'gender':user_obj.get_gender_display(),
        #                       })
        # res = json.dumps(user_list)
        res = serializers.serialize('json',user_queryset)   # 注意此处json为字符串
        # return render(request,'ab_se.html',locals())
        return HttpResponse(res)

    注意:在 http://www.bejson.com/ 中可以在线JSON格式化校验

    其结果为

     1 [{
     2     "model": "app01.userinfo",
     3     "pk": 1,
     4     "fields": {
     5         "username": "jason",
     6         "password": "123",
     7         "gender": 1
     8     }
     9 }, {
    10     "model": "app01.userinfo",
    11     "pk": 2,
    12     "fields": {
    13         "username": "tank",
    14         "password": "234",
    15         "gender": 2
    16     }
    17 }, {
    18     "model": "app01.userinfo",
    19     "pk": 3,
    20     "fields": {
    21         "username": "egon",
    22         "password": "456",
    23         "gender": 3
    24     }
    25 }, {
    26     "model": "app01.userinfo",
    27     "pk": 4,
    28     "fields": {
    29         "username": "sean",
    30         "password": "678",
    31         "gender": 4
    32     }
    33 }]
    View Code

     批量插入

    def ab_bc(request):
        # 先插入1000条数据
        # for i in range(1,1001):
        #     models.Book.objects.create(title='第%s本书'%i)
        book_list =[]
        for i in range(1,10001):
            book_list.append(models.Book(title='新的%s书'%i))
        models.Book.objects.bulk_create(book_list)  # 批量插入数据的方式
    
        book_queryset = models.Book.objects.all()
        return render(request,'ab_bc.html',locals())

    自定义分页器

    分页器组件

    class Pagination(object):
        def __init__(self,current_page,all_count,per_page_num=10,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)

    后端代码

    current_page = request.GET.get('page', 1)    # 当前页数
    all_count = book_queryset.count()     # 数据总条数
    # 1 现生成一个自定义分页器类对象
    page_obj = Pagination(current_page=current_page,all_count=all_count,pager_count=9)
    # 2 针对真实的queryset数据进行切片操作
    page_queryset = book_queryset[page_obj.start:page_obj.end]
    return render(request,'ab_bc.html',locals())

    前端代码

    {% for book_obj in page_queryset %}
        <p>{{ book_obj.title }}</p>
    {% endfor %}
    {{ page_obj.page_html|safe }}

    ajax结合sweetalert实现删除二次确认

    弹窗组件参考:https://lipis.github.io/bootstrap-sweetalert/ 

    代码:

    views.py

    
    
    from app01 import models
    from django.http import JsonResponse
    import time
    def show_user(request):
        '''
        前后端如果是通过ajax进行交互  那么交互的媒介一般情况下都是一个字典
        :param request:
        :return:
        '''
        if request.method == 'POST':
            time.sleep(3)   # 模拟延迟3秒处理再删除
            back_dic = {'code':1000,'msg':''}
            delete_id = request.POST.get('delete_id')
            models.Userinfo.objects.filter(pk=delete_id).delete()
            back_dic['msg'] = '删除成功, 准备跑路!!!'
            return JsonResponse(back_dic)
        user_queryset = models.Userinfo.objects.all()
        return render(request,'show_user.html',locals())

    models.py

    from django.db import models
    
    class Userinfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
        gender_choices = ((1,'male'),(2,'female'),(3,'other'))
        gender = models.IntegerField(choices=gender_choices)

    templates/show_user.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
        {% load static %}
        <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
        <script src="{% static 'dist/sweetalert.min.js' %}"></script>
        <style>
            div.sweet-alert h2{
                padding-top: 10px;
            }
        </style>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <h2 class="text-center">数据展示</h2>
                <table class="table-hover table table-stiped">
                    <thead>
                        <tr>
                            <th>主键</th>
                            <th>用户名</th>
                            <th>密码</th>
                            <th>性别</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for user_obj in user_queryset %}
                            <tr>
                                <td>{{ user_obj.pk }}</td>
                                <td>{{ user_obj.username }}</td>
                                <td>{{ user_obj.password }}</td>
                                <td>{{ user_obj.get_gender_display }}</td>
                                <td>
                                    <a href="#" class="btn btn-primary btn-xs">编辑</a>
                                    <a href="#" class="btn btn-danger btn-xs cancel" data_id = '{{ user_obj.pk }}' >删除</a>
                                </td>
                            </tr>
                        {% endfor %}
                        
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script>
        $('.cancel').click(function () {
            var $aEle = $(this);    {#  this 指代当前点击对象  #}
            swal({
                  title: "你确定要删嘛?",
                  text: "你如果删了,你就要准备跑路了",
                  type: "warning",
                  showCancelButton: true,
                  confirmButtonClass: "btn-danger",
                  confirmButtonText: "是,老子就是要删!",
                  cancelButtonText: "惹不起惹不起!",
                  closeOnConfirm: false,
                  closeOnCancel: false,
                    showLoaderOnConfirm: true   // 确认延迟参数
            },
            function(isConfirm) {
              if (isConfirm) {
                  // 发送ajax请求
                $.ajax({
                    url:'',
                    type:'post',
                    data:{'delete_id':$aEle.attr('data_id')},
                    success:function (data) {   // 回调函数会自动将二进制的json格式数据 解码并反序列成js中的数据类型
                        if (data.code == 1000){
                            swal("删了!", "你可以跑路了.", "success");
                            // 方式一 页面刷新
                            {#window.location.reload()    #}
                            // 方式二 DOM操作动态修改
                            $aEle.parent().parent().remove()
                        }else{
                            swal('发生了未知的错误','error')    // 将标签直接移除
                        }
                    }
                });
              } else {
                swal("怂逼", "你成功的刷新我对你的认知 :)", "error");
              }
            });
        })
    </script>
    
    </body>
    </html>

        

  • 相关阅读:
    scrapy爬虫爬取小姐姐图片(不羞涩)
    scrapy爬虫登录edusrc查看漏洞列表
    代码审计【根据功能点定向审计】BugFree ZSWin重装案例
    645-2007协议解析
    最近总结
    防爆zigbee模块
    物联网卡余额管理软件更新
    激光+紫外催化控制器
    modbus转edp协议
    modbus转mqtt工具
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12178133.html
Copyright © 2011-2022 走看看