返回总目录页

ajax相关

 

 

1.csrf装饰器

from django.shortcuts import render, redirect, HttpResponse

from django.views import View

from django.conf import global_settings
from django.contrib.sessions.backends import db

class Login(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'login.html')

    def post(self, request, *args, **kwargs):
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')
        if username == 'mcw' and pwd == '123':
            url = request.GET.get('return_url')
            if url:
                ret = redirect(url)
            else:
                ret = redirect('/index/')
            # ret['Set-Cookie'] = 'is_login=100; Path=/'
            # ret.set_cookie('is_login', '1')  # Set-Cookie: is_login=1; Path=/
            # ret.set_signed_cookie('is_login', '1', 's21',max_age=10000,)  # Set-Cookie: is_login=1; Path=/
            # 设置设session
            request.session['is_login'] = 1
            # request.session.set_expiry(0)
            return ret
        return render(request, 'login.html', {'error': '用户名或密码错误'})


def login_required(func):
    def inner(request, *args, **kwargs):
        # is_login = request.COOKIES.get('is_login')
        # is_login = request.get_signed_cookie('is_login', salt='s21', default='')
        is_login = request.session.get('is_login')
        print(is_login)
        url = request.path_info
        if is_login != 1:
            return redirect('/login/?return_url={}'.format(url))
        # 已经登录
        ret = func(request, *args, **kwargs)

        return ret

    return inner


@login_required
def index(request):
    # 获取到cookie
    print(request.session.session_key)
    request.session.clear_expired()

    return HttpResponse('首页')


@login_required
def home(request):
    return HttpResponse('home')


def logout(request):
    ret = redirect('/login/')
    # ret.delete_cookie('is_login')
    # request.session.delete()    # 删除session数据  不删除cookie
    request.session.flush()      # 删除session数据  删除cookie
    return ret
view.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
{#    {% csrf_token %}#}
    <p>
        用户名: <input type="text" name="username">
    </p>
    <p>
        密码: <input type="password" name="pwd">
    </p>
    <p>{{ error }}</p>

    <button>提交</button>
</form>


</body>
</html>
login.html
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/',views.Login.as_view()),
    url(r'^index/',views.index),
    url(r'^home/',views.home),
    url(r'^logout/',views.logout),
]
url.py
from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie
csrf_exempt   某个视图不需要进行csrf校验
csrf_protect  某个视图需要进行csrf校验
ensure_csrf_cookie  确保生成csrf的cookie
csrf_exempt      exempt意思豁免

配置文件打开csrf校验:

页面中没有使用csrf:

这样当从登陆页面post请求登陆的时候不能通过校验:这时候是开启了csrf校验但是页面没有使用csrf,也就是没有添加csrf的那个隐藏标签,就被拒绝掉了

现在是全局使用了csrf校验的。我想给某些不需要加校验,导入豁免和保护的这两个内容,并将它们以传参到登录页面的装饰器中

添加dispatch方法,将带有csrf_exempt函数名的装饰器给dispatch方法才能生效。执行父方法。加在get,post方法上当发送post请求时还是报403错误:

添加装饰器到类上,没有指定添加装饰器的是哪个方法 :

在类上面指定装饰的函数是它,指定其它的方法是报错的。校验不通过:

小结:csrf_exempt 某个视图不需要进行csrf校验

现在将settings里的csrf注释掉,所有的连接都不用添加csrf校验,正常是所有的post请求都不需要csrf验证了:

然后将csrf_protect作为参数传给方式装饰器执行,post请求又使用csrf保护起来了。

 

这里注释的:

 这里添加了csrf

登录页面也打开了:

打印提示:

然后发送登录的post请求:没有csrf_token的cookie

导入并放在get请求上:

当发送get请求的时候确保生成csrf cookie了

现在有csrftoken,且有隐藏的csrf,这样就可以提交了



2.csrf功能

 

1.csrf中间件中执行process_request:

查看这个类:

私有方法以及中间件要 定义的几个方法 ;

请求之后先执行process_request这个方法,这个方法又会去执行_get_token方法

_get_token方法判断的是全局中的一个变量

默认是False:

 

1. 从cookie中获取到csrftoken的值

cookie的名字在请求对象中是这个,并且获取它的值:

2. csrftoken的值放入到 request.META
将cookie放进去并执行这个方法

如果你传过来的长度是这个:

长度乘积之后64,:

也就是获取到的这个值是64,然后就把他返回:

通过配置文件大小在这里判断它是64,又赋值给下面这个变量;

 如果从cookie中获取的csfrtoken长度和配置计算后长度不同,就重新设置cookie,否则就返回这个cookie值

也就是下面这一步的操作是获取这个cookie值,

如果获取到了这个cookie值,那么就将它放到请求头里面,这样就能通过这个属性取请求头中cookie值;

 下一步就是从请求对象中获取这个属性,csrf处理完成了就返回None。

如果上面if没走就走下面的if,拿callback,callback就是我们要执行的函数

比如登陆CBV中的post中获取csfr_exempt,豁免,不需要校验

csrf_exempt里面设置了一个属性是True

拿到这个属性值的是这里:

下面就是请求方式的判断,如果不在这些方式里就走下面的代码,否则就返回下面的_accept()

而返回的这里就是将请求对象的csrf处理完成设置成校验完成了,返回None函数结束

下面看一下进行csrf校验:

如果请求方式不在这些(post)里面那么就执行里面的代码:

 

 如果获取到请求对象中的不设置csrf检查就返回_accept(),也就是返回一个None,csrf检查完成

https请求才会走下面:

下面就是将我们设置进请求对象中的csrf_cookie再获取出来,这个值就是我们从浏览器发给我们的csrftoken值。

这个cookie如果获取不到的话就拒绝

 

私有方法拒绝就是警告禁止403,获取一个失败的视图,这也就是说没有cookie的话不行,就执行这个错误显示视图函数

如果不是 空那么就是获取到csrftoken,那么将下面的设置为空字符串:

如果发送的是post请求,那么尝试在post键值对中获取csrf中间件token的值。前面给它赋值空字符串,后面将POST中取到的这个值再赋值给这个变量

即请求页面form表单中使用csrf创建的值:

当前不为空,那么下面又执行了如下方法:

这个方法还是那个64位判断的方法,它返回的还是token它本身:

然后继续往下执行,进行比较。比较加盐的这两个cookie值。成功返回true,失败返回false。也就是比较not 成功,那么拒接掉

如果比较成功那么不走下面的代码,而是返回的校验完成的私有方法

再看看如果获取的页面中的csrf中间件token是空,做的是下面的操作

获取的就是请求对象中的这个属性值

 获取到之后还是和cookie的值做对比。

对比的cookie值是这个:

 

 

如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。

如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。

这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。

 

两个对比,拿cookie和页面中 {% csrf_token %}或者请求头中的x...对比

 

综上:

 

2.执行process_view

  1. 查询视图函数是否使用csrf_exempt装饰器,使用了就不进行csrf的校验

  2. 判断请求方式:

    1. 如果是GET', 'HEAD', 'OPTIONS', 'TRACE'

      不进行csrf校验

      1. 其他的请求方式(post,put)

      进行csrf校验:

      1.获取cookie中csrftoken的值

      获取csrfmiddlewaretoken的值

      能获取到 ——》 request_csrf_token

      获取不到 ——》 获取请求头中X-csrftoken的值 ——》request_csrf_token

      比较上述request_csrf_token和cookie中csrftoken的值,比较成功接收请求,比较不成功拒绝请求。

3.ajax

https://www.cnblogs.com/maple-shaw/articles/9524153.html

js中json序列化和反序列化:

 

1.发请求的方式

1.地址栏输入地址 GET

2.form表单 GET/POST

3.a标签 GET

2.ajax

就是使用js的技术发请求和接收响应的。

特点:

  1. 异步  #发送一个请求过去之后不用等到结果回来就可以进行发送下一个ajax请求

  2. 局部刷新

  3. 传输的数据量少

鼠标点进去:

失焦就有提示,js事件

如果 填写注册名字已经被使用,会提示出来,这是ajax和后台交互,局部刷新的效果

如下:当写入被使用了的用户名的时候会发送请求,请求url是检查名字

返回的内容是字符串:

当写入的是没有被使用的时候,返回的是True:

  1. 局部刷新

  2. 传输的数据量少

 

 

 

3.jqery发ajax请求

$.ajax({
    url: '/calc/',
    type: 'post',
    data: {
        a: $("[name='i1']").val(),
        b: $("[name='i2']").val(),
    },
    success: function (res) {
        $("[name='i3']").val(res)
    },
    error:function (error) {
        console.log(error)
    }
})

 代码逻辑如下:

 当你输入i1和i2点击计算的时候,后端获取到输入的id,i2,并将它们运算结果i3渲染到index.html然后返回给浏览器。

如果再来一个计算的框,那么需要再来一次(或几次)基本上是重复的代码:

 

下面需要很多重复的代码:

对于单一的这种情况没有必要重复性写,应该计算哪个后端发送计算结果前端进行渲染

这里不需要values了,我们需要在视图函数中接收ajax的data传递过来的数据,并将数据在函数中操作(两数之和)之后返回给ajax,然后通过js将返回来的结果渲染在页面中,实现局部刷新。

因为我们点击button的时候它会往form表单发送请求。当我们需要使用ajax传输的时候,可以不需要form表单,或者给提交按钮添加type=button。并且

这样就实现了点击计算按钮走的是ajax请求里面的url路径

 这样就正常了

将httpresponse的值使用ajax将它渲染在页面中:

设置值,$('属性选择器(这就属性=‘啥’,不用加标签名字也可以的)')  ,jq对象.val('值')设置jq获取的标签内容

添加内部错误:

点击计算后打印:

添加页面中点击第二个计算按钮的视图函数,前端页面修改好,让它走第二个ajax的url,而不是默认的form表单(去掉form表单或者将button按钮设置类型为button)。如下设置两个视图函数,第一个视图函数结果返回设置慢一点。

点击完1就点击2,1返回慢,所以2的先回来;这样就能看出ajax请求是异步的。

 

ajax参数

添加^test/路由,添加test视图函数

点击参数之后浏览器控制台成功打印服务器返回给ajax请求的httpresponse内容

 

 但是后台传过来的是键[]作为新的字典的键了,这样的话从POST中取前端传过了的hobby键(值是有多个内容的列表)是获取不到内容的,因为名字改掉了。现在要取这些值的话需要使用字典.get('hobby[]')。

但是这里只取到最后一个,

所以应该用getlist

由于前端ajax传到后台的是字典对象,会进行url编码,会将列表做转化。我们可以直接传过去将列表格式化成字符串

 

这样后台拿到的有列表的键就是这个键了,而列表内容是字符串,后端可以做:

在后端我们可以自己将字符串序列化:

 

4.上传文件:

<input type="file" id="f1">
<button id="b1">上传</button>
​
​
$('#b1').click(function () {
        var  formobj =  new FormData();
​
        formobj.append('file',document.getElementById('f1').files[0]);
        // formobj.append('file',$('#f1')[0].files[0]);
        formobj.append('name','alex');
​
        $.ajax({
            url: '/upload/',
            type: 'post',
            data:formobj ,
            processData:false,  // 
            contentType:false,
            success: function (res) {
                $("[name='i3']").val(res)
            },
        })
    })

写上传的视图函数,上传的页面和url

现在上传没有任何效果,我们应该用ajax传输。点击按钮事件之后发送ajax请求:button添加id,选择标签,绑定点击事件,内部执行ajax请求

创建表单数据对象
对象.append(键值对),键是名字,值是file类型的input标签的DOM对象.flies[0]
DOM对象可以直接创建文档.获得元素通过id,也可以jq获取标签然后[0]转为DOM对象。我们可以往对象里面添加其他键值对。

 

 

请求url,请求类型,data数据,就是我们创建的对象
添加processData:false,处理数据格式,默认处理的,还有contetType也是false不让它处理

选择文件上传;

 

文件有了,formobj中其它参数也有了:也就是当我们上传文件时,这里没用form表单,上传走的是ajax中的url,然后用new 表单数据创建这个对象,将这个对象发送给后端,视图函数中request.FILES就是文件对象,POST就是往这个对象中添加的其它键值对,并且是个字典

contenType如果true的话会当成url编码去传,文件数据是传不过去的,false的话是表单数据传

内容类型默认url编码,在这里可以查看

 

5.ajax通过csrf的校验:

开启csrf校验之后,ajax就有问题了

前提条件:确保有csrftoken的cookie

在页面中使用{% csrf_token %}

加装饰器 ensure_csrf_cookie

from django.views.decorators.csrf import csrf_exempt,csrf_protect, ensure_csrf_cookie

1.给data中添加csrfmiddlewaretoken的值

data: {
    'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val(),
    a: $("[name='i1']").val(),
    b: $("[name='i2']").val(),
},

 开启csrf,页面添加:

 get请求页面就能返回一个csrftoken

并且页面中也有了hidden标签:

我发送ajax请求时应该将cookie也携带过去,所有ajax中要将这个input标签的键值对放到ajax的data中的对象

 

2.加请求头

headers:{
    'x-csrftoken':$('[name="csrfmiddlewaretoken"]').val(),
},

 将页面中的csrf中间件token值放到请求头这个属性中:

源码中这里写死了

请求头:

在settings中设置会覆盖全局的:这样设置,请求头属性名字在全局配置中的被它覆盖掉,用小写asd会显示在浏览器请求头上

ajax传的话是这样的:

3.使用文件

https://www.cnblogs.com/maple-shaw/articles/9524153.html

 添加一个文件

从你的本地读取到cookie,根据name获取到你的值,通过js获取到请求头中的csrftoken

 

 

AJAX准备知识:JSON

什么是 JSON ?

  • JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
  • JSON 是轻量级的文本数据交换格式
  • JSON 独立于语言 *
  • JSON 具有自我描述性,更易理解

* JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 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;}  // 不能使用函数和日期对象
}
复制代码

stringify与parse方法

JavaScript中关于JSON对象和字符串转换的两个方法:

JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象 

JSON.parse('{"name":"alex"}');
JSON.parse('{name:"alex"}') ;      // 错误
JSON.parse('[18,undefined]') ;     // 错误

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

JSON.stringify({"name":"alex"})

和XML的比较

JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。

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

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

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

 XML格式数据

用JSON表示如下:

 JSON格式数据

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

AJAX简介

AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

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

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

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

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

示例

页面输入两个整数,通过AJAX传输到后端计算出结果并返回。

 HTML部分代码
复制代码
def ajax_demo1(request):
    return render(request, "ajax_demo1.html")


def ajax_add(request):
    i1 = int(request.GET.get("i1"))
    i2 = int(request.GET.get("i2"))
    ret = i1 + i2
    return JsonResponse(ret, safe=False)
复制代码
 urls.py

AJAX常见应用情景

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

还有一个很重要的应用场景就是注册时候的用户名的查重。

其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来

  • 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
  • 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

       

 

当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示用户名已被注册!

  • 整个过程中页面没有刷新,只是局部刷新了;
  • 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;

AJAX的优缺点

优点:

  • AJAX使用JavaScript技术向服务器发送异步请求;
  • AJAX请求无须刷新整个页面;
  • 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高; 

jQuery实现的AJAX

最基本的jQuery发送AJAX请求示例:

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>ajax test</title>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<button id="ajaxTest">AJAX 测试</button>
<script>
  $("#ajaxTest").click(function () {
    $.ajax({
      url: "/ajax_test/",
      type: "POST",
      data: {username: "Q1mi", password: 123456},
      success: function (data) {
        alert(data)
      }
    })
  })
</script>
</body>
</html>
复制代码

views.py:

def ajax_test(request):
    user_name = request.POST.get("username")
    password = request.POST.get("password")
    print(user_name, password)
    return HttpResponse("OK")

$.ajax参数

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

复制代码
  $("#b1").on("click", function () {
    $.ajax({
      url:"/ajax_add/",
      type:"GET",
      data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])},
      success:function (data) {
        $("#i3").val(data);
      }
    })
  })
复制代码

JS实现AJAX

1
2
3
4
5
6
7
8
9
10
11
12
13
var b2 = document.getElementById("b2");
  b2.onclick = function () {
    // 原生JS
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST""/ajax_test/", true);
    xmlHttp.setRequestHeader("Content-type""application/x-www-form-urlencoded");
    xmlHttp.send("username=q1mi&password=123456");
    xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        alert(xmlHttp.responseText);
      }
    };
  }; 

AJAX请求如何设置csrf_token

方式1

通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

复制代码
$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  data: {
    "username": "Q1mi",
    "password": 123456,
    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
  },
  success: function (data) {
    console.log(data);
  }
})
复制代码

方式2

通过获取返回的cookie中的字符串 放置在请求头中发送。

注意:需要引入一个jquery.cookie.js插件。

复制代码
$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 从Cookie取csrftoken,并设置到请求头中
  data: {"username": "Q1mi", "password": 123456},
  success: function (data) {
    console.log(data);
  }
})
复制代码

或者用自己写一个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');
复制代码

每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为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);
    }
  }
});
复制代码

注意:

如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。

如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。

这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。

复制代码
django.views.decorators.csrf import ensure_csrf_cookie


@ensure_csrf_cookie
def login(request):
    pass
复制代码

更多细节详见:Djagno官方文档中关于CSRF的内容

AJAX上传文件

复制代码
// 上传文件示例
$("#b3").click(function () {
  var formData = new FormData();
  formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
  formData.append("f1", $("#f1")[0].files[0]);
  $.ajax({
    url: "/upload/",
    type: "POST",
    processData: false,  // 告诉jQuery不要去处理发送的数据
    contentType: false,  // 告诉jQuery不要去设置Content-Type请求头
    data: formData,
    success:function (data) {
      console.log(data)
    }
  })
})
复制代码

练习(用户名是否已被注册)

功能介绍

在注册表单中,当用户填写了用户名后,把光标移开后,会自动向服务器发送异步请求。服务器返回这个用户名是否已经被注册过。

案例分析

  • 页面中给出注册表单;
  • username input标签中绑定onblur事件处理函数。
  • 当input标签失去焦点后获取 username表单字段的值,向服务端发送AJAX请求
  • django的视图函数中处理该请求,获取username值,判断该用户在数据库中是否被注册,如果被注册了就返回“该用户已被注册”,否则响应“该用户名可以注册”。

序列化

Django内置的serializers

def books_json(request):
    book_list = models.Book.objects.all()[0:10]
    from django.core import serializers
    ret = serializers.serialize("json", book_list)
    return HttpResponse(ret)

SweetAlert插件

点击下载Bootstrap-sweetalert项目

复制代码
$(".btn-danger").on("click", function () {
  swal({
    title: "你确定要删除吗?",
    text: "删除可就找不回来了哦!",
    type: "warning",
    showCancelButton: true,
    confirmButtonClass: "btn-danger",
    confirmButtonText: "删除",
    cancelButtonText: "取消",
    closeOnConfirm: false
    },
    function () {
      var deleteId = $(this).parent().parent().attr("data_id");
      $.ajax({
        url: "/delete_book/",
        type: "post",
        data: {"id": deleteId},
        success: function (data) {
          if (data.status === 1) {
            swal("删除成功!", "你可以准备跑路了!", "success");
          } else {
            swal("删除失败", "你可以再尝试一下!", "error")
          }
        }
      })
    });
})
复制代码

 

AJAX准备知识:JSON

什么是 JSON ?

  • JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
  • JSON 是轻量级的文本数据交换格式
  • JSON 独立于语言 *
  • JSON 具有自我描述性,更易理解

* JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 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;}  // 不能使用函数和日期对象
}
复制代码

stringify与parse方法

JavaScript中关于JSON对象和字符串转换的两个方法:

JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象 

JSON.parse('{"name":"alex"}');
JSON.parse('{name:"alex"}') ;      // 错误
JSON.parse('[18,undefined]') ;     // 错误

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

JSON.stringify({"name":"alex"})

和XML的比较

JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。

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

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

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

 XML格式数据

用JSON表示如下:

 JSON格式数据

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

AJAX简介

AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

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

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

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

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

示例

页面输入两个整数,通过AJAX传输到后端计算出结果并返回。

 HTML部分代码
复制代码
def ajax_demo1(request):
    return render(request, "ajax_demo1.html")


def ajax_add(request):
    i1 = int(request.GET.get("i1"))
    i2 = int(request.GET.get("i2"))
    ret = i1 + i2
    return JsonResponse(ret, safe=False)
复制代码
 urls.py

AJAX常见应用情景

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

还有一个很重要的应用场景就是注册时候的用户名的查重。

其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来

  • 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
  • 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

       

 

当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示用户名已被注册!

  • 整个过程中页面没有刷新,只是局部刷新了;
  • 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;

AJAX的优缺点

优点:

  • AJAX使用JavaScript技术向服务器发送异步请求;
  • AJAX请求无须刷新整个页面;
  • 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高; 

jQuery实现的AJAX

最基本的jQuery发送AJAX请求示例:

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>ajax test</title>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<button id="ajaxTest">AJAX 测试</button>
<script>
  $("#ajaxTest").click(function () {
    $.ajax({
      url: "/ajax_test/",
      type: "POST",
      data: {username: "Q1mi", password: 123456},
      success: function (data) {
        alert(data)
      }
    })
  })
</script>
</body>
</html>
复制代码

views.py:

def ajax_test(request):
    user_name = request.POST.get("username")
    password = request.POST.get("password")
    print(user_name, password)
    return HttpResponse("OK")

$.ajax参数

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

复制代码
  $("#b1").on("click", function () {
    $.ajax({
      url:"/ajax_add/",
      type:"GET",
      data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])},
      success:function (data) {
        $("#i3").val(data);
      }
    })
  })
复制代码

JS实现AJAX

1
2
3
4
5
6
7
8
9
10
11
12
13
var b2 = document.getElementById("b2");
  b2.onclick = function () {
    // 原生JS
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST""/ajax_test/", true);
    xmlHttp.setRequestHeader("Content-type""application/x-www-form-urlencoded");
    xmlHttp.send("username=q1mi&password=123456");
    xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        alert(xmlHttp.responseText);
      }
    };
  }; 

AJAX请求如何设置csrf_token

方式1

通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

复制代码
$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  data: {
    "username": "Q1mi",
    "password": 123456,
    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
  },
  success: function (data) {
    console.log(data);
  }
})
复制代码

方式2

通过获取返回的cookie中的字符串 放置在请求头中发送。

注意:需要引入一个jquery.cookie.js插件。

复制代码
$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 从Cookie取csrftoken,并设置到请求头中
  data: {"username": "Q1mi", "password": 123456},
  success: function (data) {
    console.log(data);
  }
})
复制代码

或者用自己写一个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');
复制代码

每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为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);
    }
  }
});
复制代码

注意:

如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。

如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。

这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。

复制代码
django.views.decorators.csrf import ensure_csrf_cookie


@ensure_csrf_cookie
def login(request):
    pass
复制代码

更多细节详见:Djagno官方文档中关于CSRF的内容

AJAX上传文件

复制代码
// 上传文件示例
$("#b3").click(function () {
  var formData = new FormData();
  formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
  formData.append("f1", $("#f1")[0].files[0]);
  $.ajax({
    url: "/upload/",
    type: "POST",
    processData: false,  // 告诉jQuery不要去处理发送的数据
    contentType: false,  // 告诉jQuery不要去设置Content-Type请求头
    data: formData,
    success:function (data) {
      console.log(data)
    }
  })
})
复制代码

练习(用户名是否已被注册)

功能介绍

在注册表单中,当用户填写了用户名后,把光标移开后,会自动向服务器发送异步请求。服务器返回这个用户名是否已经被注册过。

案例分析

  • 页面中给出注册表单;
  • username input标签中绑定onblur事件处理函数。
  • 当input标签失去焦点后获取 username表单字段的值,向服务端发送AJAX请求
  • django的视图函数中处理该请求,获取username值,判断该用户在数据库中是否被注册,如果被注册了就返回“该用户已被注册”,否则响应“该用户名可以注册”。

序列化

Django内置的serializers

def books_json(request):
    book_list = models.Book.objects.all()[0:10]
    from django.core import serializers
    ret = serializers.serialize("json", book_list)
    return HttpResponse(ret)

SweetAlert插件

点击下载Bootstrap-sweetalert项目

复制代码
$(".btn-danger").on("click", function () {
  swal({
    title: "你确定要删除吗?",
    text: "删除可就找不回来了哦!",
    type: "warning",
    showCancelButton: true,
    confirmButtonClass: "btn-danger",
    confirmButtonText: "删除",
    cancelButtonText: "取消",
    closeOnConfirm: false
    },
    function () {
      var deleteId = $(this).parent().parent().attr("data_id");
      $.ajax({
        url: "/delete_book/",
        type: "post",
        data: {"id": deleteId},
        success: function (data) {
          if (data.status === 1) {
            swal("删除成功!", "你可以准备跑路了!", "success");
          } else {
            swal("删除失败", "你可以再尝试一下!", "error")
          }
        }
      })
    });
})
复制代码
posted @ 2019-06-27 15:08  马昌伟  阅读(121)  评论(0)    收藏  举报
博主链接地址:https://www.cnblogs.com/machangwei-8/