Django【十】Ajax

一、Ajax基本用法

1.简介

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

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

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

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

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

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

   AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程

2.示例

html页面内容:

复制代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% csrf_token %}

用户名:<input type="text" id="i1" name="usename">
<input type="button" value="提交" id="but">
<span class="s1"></span>
</body>
<script src="{% static "jquery-3.4.1.js" %}"></script>
<script>

    $("#but").click(function () {
        var name = $("#i1").val();
        var csrf_data = $('[name=csrfmiddlewaretoken]').val();
        $.ajax(
            {
                url:"{% url 'login' %}",
                type:"post",
                data:{
                        name:name,
                        csrfmiddlewaretoken:csrf_data,
                    },
                success:function (data) {
                    if (data==="123"){
                        alert("登陆成功")
                    }else {
                        $(".s1").text("用户名或密码错误!!!")
                    }
                }
            }
        )
    })

</script>

</html>
复制代码

views内容:

复制代码
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from app01 import models
def index(request):

    return render(request,"index.html")

def login(request):
    print(request.POST)
    data = request.POST.get("name")
    print(data)
    # <QueryDict: {'name': ['123'], 'csrfmiddlewaretoken': ['8lbAt5pr33TaApmK1I8UVUNgiY62uAp4qJoBjdH8oSt5XNe2eMd9XUd3daFKV8A9']}>
    return HttpResponse("123")
复制代码

urls内容:

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^index/', views.index,name="index"),
    url(r'^login/', views.login,name="login"),
]

3.AJAX常见应用情景

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

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

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

      a.整个过程中页面没有刷新,只是刷新页面中的局部位置而已!

      b.当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

           

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

    a.整个过程中页面没有刷新,只是局部刷新了;

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

二、上传文件

1、基于from表单上传文件

URLS:

from app01 import views
urlpatterns = [
    url(r'^upload/', views.upload,name="upload"),
]

HTML:

复制代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="{% url "upload" %}" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    用户名:<input type="text" name="username">
    头像:<input type="file" name="file">
    <input type="submit" value="提交" id="sub">
</form>

</body>
<script src="{% static "jquery-3.4.1.js" %}"></script>

</html>
复制代码

views:

复制代码
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

def upload(request):
    if request.method=="GET":
        return render(request,"upload.html")
    else:
        username = request.POST.get("username")  # 获取用户输入的内容
        file_obj = request.FILES.get("file")   # 获得文件数据对象
        print(username,file_obj.name)
        # 获取文件名字
        file_name = file_obj.name
        with open(file_name,"wb") as f:
            # for data in file_obj:   #读取数据
            #    f.write(data)     #每次读取的data不是固定长度的,和读取其他文件一样,每次读一行,识别符为
  
  
,遇到这几个符号就算是读了一行


            for data in file_obj.chunks():  #chunks()默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M,是一个生成器
                f.write(data)

        return HttpResponse("ok")
复制代码

2、基于Ajax的文件上传

HTML:

复制代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div> <!--只是一个盒子,用不用都行-->
    {% csrf_token %}
    用户名:<input type="text" name="username">
    头像:<input type="file" name="file">
    <input type="button" value="提交" id="sub">
</div>

</body>
<script src="{% static "jquery-3.4.1.js" %}"></script>

<script>

    $("#sub").click(function () {
        // ajax上传文件的时候,需要这个类型,它会将添加给它的键值对加工成formdata的类型
        var formdata=new FormData();
        // 添加键值的方法是append,注意写法,键和值之间是逗号
        formdata.append("name",$("[type=text]").val());
        // 转换成DOM对象
        formdata.append("file",$("[type=file]")[0].files[0]);

        // 别忘了csrf_token
        formdata.append("csrfmiddlewaretoken",$("[name=csrfmiddlewaretoken]").val());
        $.ajax({
                url:{% url "upload" %},
                type:"post",
                data:formdata,          // 将添加好数据的formdata放到data这里
                processData: false ,    // 不处理数据
                contentType: false,     // 不设置内容类型
                success:function (response) {
                    console.log(response)
                }
            }
        )

    })
</script>

</html>
复制代码

其他代码同上:

注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。

三、请求头Content Type

ContentType指的是请求体的编码类型,常见的类型共有3种:

1、第一种请求方式:application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。请求类似于下面这样

数据是以&符连接的:上面这种contenttype规定的数据格式,后端对应这个格式来解析获取数据,不管是get方法还是post方法,都是这样拼接数据,大家公认的一种数据格式,但是如果你contenttype指定的是urlencoded类型,但是post请求体里面的数据是下面那种json的格式,那么就出错了,服务端没法解开数据。

2、第二种请求方式:multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data,form表单不支持发json类型的contenttype格式的数据,而ajax什么格式都可以发,也是ajax应用广泛的一个原因。直接来看一个请求示例:(了解)

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

      这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

      上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

      随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

3、第三种请求方式:application/json

客户端如果指定以json作为请求体的编码类型,那么服务端在接收后也要以对应的数据格式进行解码:
Django不支持json格式的编码类型,若浏览器请求使用json这种编码类型发送请求的那么就需要我们自定义解析器,对数据进行解析:
HTML代码:
复制代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div>

    用户名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <input type="button" value="提交" id="btn">
</div>

</body>

<script src="{% static "jquery-3.4.1.js" %}"></script>

<script>
    $("#btn").click(function () {

        $.ajax({
            url:{% url "index" %},
            type:"post",
            headers:{'Content-Type':'application/json'}, // 指定数据编码格式
            data:JSON.stringify({        // 对数据进行序列化
                name:$("[name=usename]").val(),
                pwd:$("[name=password]").val(),
            }),

            success:function (response) {
                console.log(typeof response);    // python序列化后的json字符串
                var dic = JSON.parse(response);  // 需要进行反序列化才可以用
                console.log(dic.info)            // 直接可以调用对应的属性
            }
        })
    })

</script>

</html>
复制代码

视图函数:

复制代码
import json
def index(request):
    if request.method=="GET":
        return render(request,"index.html")

    else:
        html_json = request.body         # 取出原数据,在对数据进行反序列化
        py_str = json.loads(html_json)   # 反序列化成字典,在处理
        print(py_str)   # {'pwd': '123'}


        res_dic = {"status":0,"info":"响应信息"}
        str_dic = json.dumps(res_dic)      # 将字典序列化成json字符串
        return HttpResponse(str_dic)        # 发送给ajax的response
复制代码

import json
def index(request):
    if request.method=="GET":
        return render(request,"index.html")

    else:
        html_json = request.body          # 取出原数据,在对数据进行反序列化
        py_str = json.loads(html_json)   # 反序列化成字典,在处理
        print(py_str)                             # {'pwd': '123'}

        res_dic = {"status":0,"info":"响应信息"}
        str_dic = json.dumps(res_dic)

        # 指定数据编码格式相当于告诉浏览器按照这个格式进行解码
        return HttpResponse(str_dic,content_type="application/json")

django指定数据格式
django指定数据格式
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div>

    用户名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <input type="button" value="提交" id="btn">
</div>

</body>

<script src="{% static "jquery-3.4.1.js" %}"></script>

<script>
    $("#btn").click(function () {

        $.ajax({
            url:{% url "index" %},
            type:"post",
            headers:{'Content-Type':'application/json'}, // 指定数据编码格式
            data:JSON.stringify({        // 对数据进行序列化
                name:$("[name=usename]").val(),
                pwd:$("[name=password]").val(),
            }),

            success:function (response) {
                console.log(response.info);      //拿到json数据类型的数据,根据服务器指定的数据编码格式调用内部的解析器进行解码
        })
    })

</script>

</html>

HTML
html

注意JsonResponse默认只处理字典类型的数据,如果想要返回其他数据类型:

总结:

1
2
form表单不支持json数据格式的传输
django不支持json数据格式的解析,需要我们自定义解析器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import json
dic={"chao":"123"}
 
dic_en = json.dumps(dic)
print(dic_en,type(dic_en))
 
 
aa = dic_en.encode("utf-8")
print(aa)
 
 
bb = json.loads(aa)
print(bb,type(bb))
 
"""
{"chao": "123"} <class 'str'>
b'{"chao": "123"}'
{'chao': '123'} <class 'dict'>
"""
# bytes类型的字典,可以直接loads成字典,不需要decode

四、序列化models对象:

1
2
3
4
5
6
from django.urls import reverse
book_objs = models.Book.objects.all().values('title','price')
# django内部序列化方法
res = serializers.serialize('json', book_objs)
# 建议用下面这种方式序列化,强转数据类型
books = list(book_objs)

通过json序列化时间日期格式数据的时候需要注意,不能直接序列化:

复制代码
import json
from datetime import datetime
from datetime import date

#对含有日期格式数据的json数据进行转换
class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field,datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field,date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self,field)


d1 = datetime.now()

dd = json.dumps(d1,cls=JsonCustomEncoder)
print(dd)
复制代码

五、Ajax通过csrf_token的几种方式

方式1

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

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

方式2

$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

方式3

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

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

复制代码
<script src="{% static 'js/jquery.cookie.js' %}"></script>

$.ajax({
 
headers:{"X-CSRFToken":$.cookie('csrftoken')}, #其实在ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加
 
})
复制代码

注意:如果我们发送的是json数据格式的数据,那么csrf_token就不能直接写在data里面了,没有效果,必须通过csrf的方式3的形式来写,写在hearders(请求头,可以写一些自定制的请求头)里面,注意,其实contentType也是headers里面的一部分,写在里面外面都可以:

六、Ajax验证登录

HTML:

复制代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% csrf_token %}

用户名:<input type="text" id="i1" name="username">
密码:<input type="text" id="i1" name="password">
<input type="button" value="提交" id="but">
<span class="s1"></span>
</body>
<script src="{% static "jquery-3.4.1.js" %}"></script>
<script>

    $("#but").click(function () {
        var username = $("[name=username]").val();
        var password = $("[name=password]").val();
        var csrf_data = $('[name=csrfmiddlewaretoken]').val();
        $.ajax(
            {
                url:"{% url 'login' %}",
                type:"post",
                data:{
                        name:username,
                        pwd:password,
                        csrfmiddlewaretoken:csrf_data,
                    },
                success:function (data) {
                    if (data==="123"){
                        alert("登陆成功");
                        location.href="{% url "index" %}"
                    }else {
                        $(".s1").text("用户名或密码错误!!!")
                    }
                }
            }
        )
    })

</script>

</html>
复制代码

视图函数:

复制代码
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from app01 import models

def index(request):
    return render(request,"index.html")


def login(request):
    if request.method=="GET":
        return render(request, "login.html")
    else:
        name = request.POST.get("name")
        pwd = request.POST.get("pwd")
        obj = models.Userinfo.objects.all()
        # 判断数据库的用户名和用户输入的的是否一致
        for info in obj:
            if name==info.username and pwd==info.password:
                return HttpResponse("123")
        else:
            return render(request,"login.html")
复制代码

URLS:

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^index/', views.index,name="index"),
    url(r'^login/', views.login,name="login"),
]

数据库用户信息表:

原文地址:https://www.cnblogs.com/youxiu123/p/11600565.html