• 27 Jun 18 Django,AJAX


    27 Jun 18

    一、内容回顾

    1. importlib

     

    # 和demo.py同目录下的pp package中的mm.py文件;文件中有一个Person类

     

    # 不使用importlib导入

    from pp import mm

    zz = mm.Person("张曌")

    print(zz.name)

     

    # 使用importlib将字符串映射导入

    import importlib

    s = "pp.mm" 

    tmp = importlib.import_module(s)  # 作用于字符串

    print(tmp)  

    # <module 'pp.mm' from '/Users/zhangyaqian/Desktop/day72/day72/pp/mm.py'>

    lsd = tmp.Person("梁书东")

    print(lsd.name)  # 梁书东

     

    2. 作业题讲解:基于中间件做一个访问频率限制,每个IP每分钟最多访问3次

     

    import datetime

     

    HISTORY = {}  # {'ip':{'last':time,'times':number},}

    BLACK_LIST = []

     

    class Throttle(MiddlewareMixin): # throttle 节流阀

     

        def process_request(self,request):

            ip = request.META.get("REMOTE_ADDR")  # 通过request找到访问ip

            now = datetime.datetime.now()  # 拿到当前时间

     

            if ip in BLACK_LIST:

                return HttpResponse("ACCESS DENIED")  

    #如果在黑名单中直接返回,不需要做更多重复无效的判断和搜索

     

            if ip not in HISTORY:

                HISTORY[ip] = {"last": now, "times": 0} # 初始化

     

            if (now - HISTORY[ip]["last"]) < datetime.timedelta(seconds=60):  

    # 注意timedelta()的用法

                HISTORY[ip]["times"] += 1

            else:

               HISTORY[ip]["times"] = 0

               HISTORY[ip]["last"] = now

     

            if HISTORY[ip]["times"] > 3:

               BLACK_LIST.append(ip)

                return HttpResponse("ACCESS DENIED: more than 3 times within 60s")

     

    3. 渲染(字符串替换)是发生在后端(views.py<->template)(渲染成完整的html文件),不是在浏览器端(接收渲染好的html文件,按照html标签显示出来)

     

    4. 如果找不到urls, django框架级别返回404,不走中间件的process_response

     

    二、今日内容

    https://www.cnblogs.com/liwenzhou/p/8718861.html

     

    1. AJAX预备知识点(JSON:JavaScript Object Notation)

    a. Python中

        import json

        json.loads() # dict <== JSON格式字符串

        json.dumps() # dict ==> SON格式字符串

     

        举例:

        import json

        d = {"name": "张曌", "age": 16}

        ret1 = json.dumps(d, indent=4)  # json.dumps()后面可可以设置一系列参数

        print(ret1)

        ret2 = json.loads(ret1)

        print(ret2)

     

    b. JavaScript中:

        JSON.parse()     # JavaScript obj <== JSON格式字符串

        JSON.stringify()   # JavaScript obj ==> JSON格式字符串

     

    # 日期对象要先转化成字符串,才能继续序列化

    # 不能使用undefined. 在JSON中为null

     

    2. AJAX (Asynchronous Javascript And XML)

    a. AJAX: 使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML);其最开始传输的主要是XML,目前依旧可以用来传输XML,但主要用来传输更精简的JSON等

     

       AJAX和FORM表达:

       AJAX:主要应用于用户无感的区域(页面不刷新,后端查数据)

       FORM:页面刷新

     

       AJAX主要的应用场景:

       1) 搜索引擎根据用户输入的关键字,自动提示检索关键字。

       2) 注册时候的用户名的查重。

     

     

    b. jQuery实现的AJAX (示例:页面输入两个整数,通过AJAX传输到后端计算出结果并返回。)

    # 可以用jQuery实现,也可用JS实现AJAX;用jQuery实现相对便捷,但需要提前导入jQuery;用JS实现AJAX的方式需了解,不常用

     

    # AJAX_TEST.html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1">

       <title>AJAX</title>

    </head>

    <body>

     

    {# 没有做csrf token的处理,本示类注释了settings中中间件的第四行(csrf相关)#}

    <input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">

    <button id="b1">AJAX TEST</button>

    <script src="/static/jquery-3.3.1.min.js"></script>  

    # 用jQuery的方式($),必须先导入jQuery

     

    <script>

        $('#b1').click(function(){

            $.ajax({

                url: "/ajax/",

                type: 'POST',

                {# ajax 只能处理GET和POST请求#}

                data: {i1:$("#i1").val(),i2:$("#i2").val()},

                {# data参数中的键值对,如果不是字符串,需要将其转换成字符串类型。#}

                {# success 为回调函数,data为views.py中传来的结果res#}

                success: function (data) {

                    $("#i3").val(data);

                }

            })

        })

    </script>

     

    </body>

    </html>

     

    # views.py

    from django.shortcuts import render,redirect,HttpResponse

     

    def ajax(request):

        if request.method == 'POST':

           print(request.POST)  # <QueryDict: {'i1': ['12'], 'i2': ['12']}>

            i1 = request.POST.get('i1')

            i2 = request.POST.get('i2')  # 得到的是字符串

            res = int(i1) + int(i2)  # 必须先转化成int类型,才能做进一步运算

            return HttpResponse(res)

        return render(request,'AJAX_TEST.html')

     

    c. AJAX优缺点

    1)优点:

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

        异步:在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作

    2)缺点:

        服务端压力大:滥用AJAX(大量的button绑定AJAX),导致后段需要维护好多API,导致服务端压力大,进而影响性能

     

    #补充:

    同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

    异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

     

    d. AJAX处理csrf_token

    1) 方式一:通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

    # {% csrf_token%} 的本质为隐藏的input框

     

    # .html中:

    {% csrf_token %}

     

    $("#b11").click(function () {

            // 点击之后要做的事儿

            $.ajax({

                url: "/ajax_test2/",

                type: "POST",

     

                data: {

                    i11: $("#i11").val(),

                    i22: $("#i22").val(),

                    // 使用JQuery取出csrf_token中csrfmiddlewaretoken的值,拼接到data中

                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()

                },

     

                success: function (data) {

                   console.log(data);

                   $("#i33").val(data);

                }

            })

        });

     

    2) 方式二:通过获取返回的cookie中的字符串放置在请求头中发送(不需在html中加入隐藏的input框{% csrf_token%})。(需要引入一个jquery.cookie.js插件。)

    # jquery.cookie.js依赖于jQuery,先导入jQuery再导入jquery.cookie.js

     

    # .html中:

     

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/jquery.cookie.js"></script>

     

    $("#b22").click(function () {

            $.ajax({

                url: "/ajax_test2/",

                type: "POST",

                headers: {"X-CSRFToken": $.cookie('csrftoken')},  

    // 从Cookie取csrf_token,并设置ajax请求头

                data: {

                    i11: $("#i11").val(),

                    i22: $("#i22").val(),

                },

     

                success: function (data) {

                   console.log(data);

                   $("#i33").val(data);

                }

            })

        });

     

    3) 方式三:使用$.ajaxSetup()方法为ajax请求统一设置

    # 在static中配置setupAjax.js文件,使用前导入; 在后续调用$.ajax的过程中不需再做额外的配置

     

    # setupAjax.js

    // 自己写一个getCookie方法

    function getCookie(name) {

        var cookieValue = null;

        if (document.cookie && document.cookie !== '') {

            var cookies = document.cookie.split(';');

            for (var i = 0; i < cookies.length; i++) {

                var cookie = jQuery.trim(cookies[i]);

                // Does this cookie string begin with the name we want?

                if (cookie.substring(0, name.length + 1) === (name + '=')) {

                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));

                    break;

                }

            }

        }

        return cookieValue;

    }

    var csrftoken = getCookie('csrftoken');

     

    // 为ajax请求统一设置

    function csrfSafeMethod(method) {

      // these HTTP methods do not require CSRF protection

      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));

    }

     

    $.ajaxSetup({

      beforeSend: function (xhr, settings) {

        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {

         xhr.setRequestHeader("X-CSRFToken", csrftoken);

        }

      }

    });

     

    # .html中:

     

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/setupAjax.js"></script>

     

    // 点击b33

    $("#b33").click(function () {

        $.ajax({

            url: "/ajax_test2/",

            type: "POST",

            data: {

                i11: $("#i11").val(),

                i22: $("#i22").val(),

            },

     

            success: function (data) {

                console.log(data);

               $("#i33").val(data);

            }

        })

    });

     

    e. AJAX上传文件

    # views.py

     

    def upload(request):

        if request.method == "POST":

            print(request.POST)

            file_obj = request.FILES.get("f1")

            # 通过.FILES取文件

            with open(file_obj.name, "wb") as f:

                for chunk in file_obj.chunks():

                    f.write(chunk)

            return HttpResponse("O98K")

        return render(request, "upload.html")

     

    # upload.html

     

    {# 使用form表单,提交文件#}

    <form action="/upload/" method="post" enctype="multipart/form-data">

        {% csrf_token %}

        <input type="file" name="f1">

        <input type="submit" value="提交">

    </form>

     

    {#使用ajax,提交文件#}

    <input id="i1" type="file">

    <button id="b1">点我</button>

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/setupAjax.js"></script>

     

    <script>

       $("#b1").click(function () {

            // 先生成一个表单对象

            var formData = new FormData();

            // 向form表单对象添加键值对数据

            formData.append("f1", $("#i1")[0].files[0]);

           formData.append("name", "张曌");

            {#这种方式可以上传文件,亦可添加普通数据#}

            $.ajax({

                url: "/upload/",

                type: "POST",

                processData: false,  // 告诉jQuery不要去处理发送的数据

                contentType: false, // 告诉jQuery不要去设置Content-Type请求头

                {#data不能直接放文件($("#i1")[0].files[0]),因此要做以上操作(建立一个表单对象,然后把键值对对象添加进去)#}

                data: formData,

                {#之后的data和之前的不是一个data;前面的是提交的文件对象,后面的是后端返回的response(OK)#}

                success:function (data) {

                   console.log(data)

                }

            })

        });

     

    d. 用JS实现AJAX(了解)

     

    # views.py

    def ajax_js(request):

        if request.method == "POST":

            print(request.POST)

            return HttpResponse("OK")

        return render(request, "ajax_js.html")

     

    #ajax_js.html

    <button id="b1">点我 发送JS 版AJAX请求</button>

    <script>

        let b1Ele = document.getElementById("b1");

        b1Ele.onclick = function () {

            // 1. 生成xmlHttp对象

            let xmlHttp = new XMLHttpRequest();

            // 2. 调用xmlHttp的open方法设置请求相关配置项

            xmlHttp.open("POST", "/ajax_js/", true);

            // 3. 设置请求头

           xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

            // 4. 调用send方法发送数据

            xmlHttp.send("username=张曌&age=16");

            // 5. 处理返回的响应

            xmlHttp.onreadystatechange = function () {

                if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {

                    alert(xmlHttp.responseText);

                }

            };

        }

    </script>

     

    3. Django内置的serializers

    # 把QuerySet对象转成字符串可以用Json,也可以用serializers;

    # 用Json的话,需要一个一个转,性能低。后续会经常使用serializers批量转化

     

    #.html

    $("#b44").click(function () {

        $.ajax({

            url: "/books/",

            type: "GET",

            success: function (data) {

                if (data.code === 0) {

                   console.log(data.data);  # 拿到数据库中的数据

                }

            }

        })

    });

     

    #views.py

    from django.http import JsonResponse

    # JsonResponse为HttpResponse的一个子类;接受字典转成Json格式的字符串进行进一步传输

    def books(request):

        ret = {"code": 0}

        book_list = models.Book.objects.all()

        from django.core import serializers

        data = serializers.serialize("json", book_list)

        ret["data"] = data

        return JsonResponse(ret)

     

    4. 补充(SweetAlert)

    https://github.com/lipis/bootstrap-sweetalert

     

    #views.py

    def delete_book(request):

        if request.method == "POST":

            delete_id = request.POST.get("id")

            import time

            time.sleep(2)  # 可以看出showLoaderOnConfirm: true 的效果

           models.Book.objects.filter(id=delete_id).delete()

            ret = {"code": 0}

            return JsonResponse(ret)

     

    # .html

    <link rel="stylesheet" href="/static/sweetalert/sweetalert.css">

     

    $("#b55").click(function () {

            swal({

                        title: "你确定要删除吗?",

                        text: "删除可就找不回来了哦!",

                        type: "warning",

                        showCancelButton: true,  // 是否显示取消按钮

                        confirmButtonClass: "btn-danger",  // 确认按钮的样式类

                        confirmButtonText: "删除",  // 确认按钮文本

                        cancelButtonText: "取消",  // 取消按钮文本

                        closeOnConfirm: false,  // 点击确认按钮不关闭弹框

                        showLoaderOnConfirm: true  // 显示正在删除的动画效果

                    },

                    function () {

                        var deleteId = 2;

                        $.ajax({

                            url: "/delete_book/",

                            type: "post",

                            data: {"id": deleteId},

                            success: function (data) {

                                if (data.code === 0) {

                                    swal("删除成功!", "你可以准备跑路了!", "success");

                                } else {

                                    swal("删除失败", "你可以再尝试一下!", "error")

                                }

                            }

                        })

                    });

        })

     

    5. 补充(echarts:画图)

    http://echarts.baidu.com/download.html

    下载并导入<script src="/static/echarts.simple.min.js"></script>

     

    # views.py

     

    data = {

        "date": ["2018-01", "2018-02", "2018-03", "2018-04", "2018-05"],

        "code_amount": [1200, 1000, 800, 600, 12000]

    }

     

    def demo(request):

        if request.method == "POST":

            return JsonResponse(data)

        return render(request, "demo.html")

     

    # demo.html

     

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/echarts.simple.min.js"></script>

     

    <script>

        // 基于准备好的dom,初始化echarts实例

        var myChart = echarts.init(document.getElementById('main'));

        // 使用AJAX向后端请求数据

        $.ajax({

            url: "/demo/",

            type: "POST",

            data: {name: "长牙签"},

            success: function (data) {

                // 指定图表的配置项和数据

                var option = {

                    title: {

                        text: 'ECharts 入门示例'

                    },

     

                    tooltip: {},

     

                    legend: {

                        data: ['代码量']

                    },

     

                    xAxis: {

                        data: data.date

                    },

     

                    yAxis: {},

     

                    series: [{

                        name: '代码量',

                        type: 'bar',

                        data: data.code_amount

                    }]

                };

                // 使用刚指定的配置项和数据显示图表。

               myChart.setOption(option);

     

            }

        });

    </script>

     

    6. 回顾input(用户名查重,用input事件追踪input框的内容变化)

     

    # .html

    <input type="text" id="i2">

     

    $("#i2").on("input", function () {

            console.log($(this).val())

    })

     

  • 相关阅读:
    软件工程概论第十六周学习进度表
    构建之法阅读笔记06
    软件工程概论第十五周学习进度表
    手机百度输入法的用户体验
    构建之法阅读笔记05
    软件工程概论第十四周学习进度表
    2020/2/1-Python学习计划
    Map Reduce数据清洗及Hive数据库操作
    《大数据技术原理与应用》暑假学习计划_06
    分布式数据库的安装与配置
  • 原文地址:https://www.cnblogs.com/zhangyaqian/p/py20180627.html
Copyright © 2020-2023  润新知