Ajax

1. importlib

# 和demo.py同目录下的pp package中的mm.py文件;文件中有一个Person类
# 不使用importlib导入
from pp import mm
zz = mm.Person("zzz")
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("llll")
print(lsd.name)  # llll

 

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

一、Ajax

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

a. Python中

    import json

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

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

 

    举例:

    import json

    d = {"name": "zzz", "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参数中的键值对,如果不是字符串,需要将其转换成字符串类型。如果键值对的值是类似Python列表套列表[1[1,2,3],[4,5,6]],
        那么需要加一个设置traditional为True,不然会变成[1,2,3,4,5,6];或者将其序列化成json格式。
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>
<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>
<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())
})

 

posted @ 2018-08-28 20:58  桥前石头  阅读(148)  评论(0编辑  收藏  举报