Django框架—Ajax请求
1.什么是json
json(Javascript Obiect Notation,JS对象标记)是一种轻量级的数据交换格式。
json是基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
-
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
-
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
json本质是从js中拿出来的一个对象,也可以说json是js的一个子集。也就是说json的格式来源于JS的格式。
2.json使用的规则
1.js中支持单引号,也支持双引号,可以没有引号
//在js中吧{}这样的类型叫做自定义对象,js中没有字典一说 data = { 'name':'xiongda', "name":"xiongda", name:"xiongda" } //js对象默认会把自己的键当成字符串处理,所以可以加引号也可以不加
2.json中支持的格式
-
json只认识双引号
-
json一定是一个字符串(字符串里面只能包含一个对象)
'{"name":"xiongda"}'
3.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;} // 不能使用函数和日期对象 }
3.python和js中的序列化/反序列化
python中的序列化/反序列化
python中序列化和反序列化需要导入模块json
-
json.dumps(obj):将python对象序列化为json格式字符串
-
json.loads(json对象):将json对象反序列化为python对象
import json # s = "{'name':'chao','age':18}" #普通字符串,每加引号的没问题,加了引号的,必须是双引号才能使用json.loads()。 s = '{"name":"xiongda","age":18}' #json字符串,里面必须是双引号 ret = json.loads(s) print(ret,type(ret)) # {'name': 'xiongda', 'age': 18} <class 'dict'> d = {'name': 'xiongda', 'age': 18} ret = json.dumps(d) print(ret,type(ret)) # {"name": "xiongda", "age": 18} <class 'str'>
js中的序列化和反序列化
js中的序列化和反序列化是通过JSON来实现,可以直接使用
-
JSON.stringify():将一个javascript对象转化为json字符串
-
JSON.parse():将一个json字符串转换为javascript对象
<script> // js中的json的序列化 s2={'name':'xiongda'}; console.log(JSON.stringify(s2),typeof JSON.stringify(s2)) //string // js中的json反序列化 s = '{"name":1}'; var data = JSON.parse(s); console.log(data); console.log(typeof data); //object </script>
4.json和xml的比较
-
XML也是存数据的一种格式,也是一种标记语言。它是利用节点进行查找的
-
JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。
SON 格式有两个显著的优点:
-
书写简单,一目了然;
-
符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。
所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。
json和xml使用实例
xml表示省市数据
<?xml version="1.0" encoding="utf-8"?> <country> <name>中国</name> <province> <name>黑龙江</name> <cities> <city>哈尔滨</city> <city>大庆</city> </cities> </province> <province> <name>广东</name> <cities> <city>广州</city> <city>深圳</city> <city>珠海</city> </cities> </province> <province> <name>台湾</name> <cities> <city>台北</city> <city>高雄</city> </cities> </province> <province> <name>新疆</name> <cities> <city>乌鲁木齐</city> </cities> </province> </country>
json表示省市数据
{ "name": "中国", "province": [{ "name": "黑龙江", "cities": { "city": ["哈尔滨", "大庆"] } }, { "name": "广东", "cities": { "city": ["广州", "深圳", "珠海"] } }, { "name": "台湾", "cities": { "city": ["台北", "高雄"] } }, { "name": "新疆", "cities": { "city": ["乌鲁木齐"] } }] }
可以看到,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
json的优缺点
JSON格式取代了xml给网络传输带来了很大的便利,但是却没有了xml的一目了然,尤其是json数据很长的时候,我们会陷入繁琐复杂的数据节点查找中。
但是国人的一款在线工具 BeJson 、SoJson在线工具让众多程序员、新接触JSON格式的程序员更快的了解JSON的结构,更快的精确定位JSON格式错误。
二、Ajax简介
1.什么是Ajax
Ajax(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。
即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
Ajax不是编程语言,而是一种使用现有标准的新方法,也就是前端向后端提交数据的方式。
使用Ajax的优点:
-
无需重新加载页面,异步发送请求获取服务数据。
-
局部刷新页面,增强用户体验
-
浏览器无需响应全部页面,只是页面中少数内容,所以效率高。
Ajax不需要浏览器插件,但是需要浏览器中有JavaScript环境;
-
同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
-
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
2.Ajax简单使用
我们以前知道的前端向后端发送数据的方式有:
-
GET:地址栏、a标签、Form表单
-
POST:Form表单
现在我们再学习一种:那就是ajax,也是前端向后端发送数据的一种方式
通过Ajax提交数据请求服务器,获取响应结果,根据响应结果局部更新当前页面,提示用户输入。
login.html页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% csrf_token %} 用户名:<input type="text" name="username" id="username"><br> 密码:<input type="password" name="password" id="password"><br> <input type="button" id="sub" value="提交"><br> <span class="info"></span> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> // 给sub标签绑定事件,提交数据 $('#sub').click(function(){ $.ajax({ url:"{% url 'auth' %}", // ajax异步请求的链接 type:'post', // ajax请求页面的方法 data:{ username:$('#username').val(), password:$('#password').val(), csrfmiddlewaretoken:$('input[name="csrfmiddlewaretoken"]').val() }, // 注意ajax提交数据,需要将数据封装在data中,和form提交数据不同,需要我们手动获取csrf_token的值,然后封装到data中,发送给服务端 success:function (response) { console.log(response); // response是请求成功后服务端返回的数据 if (response==="1"){ alert("帐号或密码错误!") } else{ $('.info').val('帐号密码正确') } } }) }) </script> </body> </html>
urls.py文件
from app01 import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^login/', views.login,name='login'), ]
views.py文件
def auth(request): if request.method=="POST": username = 'alex' password = 'alex' if username == request.POST.get("username") and password == request.POST.get("password"): return HttpResponse(‘2’) else: return HttpResponse('1')
3.Ajax应用场景
使用场景
1.搜索引擎根据用户输入的关键字,不用刷新页面,自动提示检索关键字。
2.注册用户时对于用户名的查重,使用了Ajax
我们输入用户名后,并没有主动发送数据请求页面,但是网页上会显示该用户名已经被占用,重新选择用户名。
-
整个过程页面没有刷新,只有局部信息刷新
-
检查用户名请求发送后,我们无需等待,可以操作浏览器
其实本质上,就是给input标签绑定了一个失焦事件,当标签失焦后,会通过ajax发送请求,判断用户名是否存在,根据返回信息,局部刷新页面,从而提示用户。
ajax的特点(优点)
-
AJAX使用Javascript技术向服务器发送异步请求;
-
AJAX无须刷新整个页面;
-
因为服务器响应内容不再是整个页面,而是页面中的局部,所以AJAX性能高;
三、Ajax的使用
1.基于jQuery实现
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'js/jquery-3.1.1.js' %}"></script> </head> <body> <button class="send_Ajax">send_Ajax</button> <script> // $.ajax的两种使用方式: // $.ajax(settings); // $.ajax(url,[settings]); $(".send_Ajax").click(function () { $.ajax({ url: "/handle_Ajax/", type: "POST", data: {username: "Yuan", password: 123}, //==================成功的时候要执行的代码================== success: function (response) { alert(response) }, //=================== error的时候要执行的代码============ error: function (jqXHR, textStatus, err) { // jqXHR: jQuery增强的xhr // textStatus: 请求完成状态 // err: 底层通过throw抛出的异常对象,值与错误类型有关 console.log(arguments); }, //============ complete(无论成功还是失败,都要执行的代码)============ complete: function (jqXHR, textStatus) { // jqXHR: jQuery增强的xhr // textStatus: 请求完成状态 success | error console.log('statusCode: %d, statusText: %s', jqXHR.status, jqXHR.statusText); console.log('textStatus: %s', textStatus); }, //============= statusCode============ statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); //注意:后端模拟errror方式:HttpResponse.status_code=500 }, '400': function () { } } }) }) </script> </body> </html>
2.基于原生js实现(了解)
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=chao&password=123456"); xmlHttp.onreadystatechange = function () { if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { alert(xmlHttp.responseText); } }; };
四、Ajax参数详解
1.请求参数
data参数
data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式(urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。
function testData() { $.ajax("/test", { //此时的data是一个json形式的对象 data: { a: 1, b: 2 } }); //?a=1&b=2 }
processData参数
processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;
if为false,那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后得到一个[object,Object]形式的结果。
contentType参数
contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。
用来指明当前请求的数据编码格式;类似urlencoded:?a=1&b=2的格式发送数据。
contentType的三种类型:
-
application/x-www-form-urlencoded;默认值,类似urlencoded:?a=1&b=2的格式发送数据
-
multipart/form-data;提交文件的格式。
-
application/json;以json格式发送数据。
详细使用见下方
traditional参数
traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]},traditional为false会对数据进行深层次迭代;
2.响应参数
dataType参数
预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容 进行一个json格式的转换。
如果转换成功,我们在success的回调函数里就会得到一个json格式的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用data Type。dataType的可用值:html|xml|json|text|script
五、Ajax跨站请求伪造csrf_token
1.手动封装键值对(推荐)
直接获取隐藏input标签的csrfmiddlewaretoken值,组成键值对放在data中发送到服务端
注意键名是csrfmiddlewaretoken固定的,不能变
$.ajax({ url: "/cookie_ajax/", type: "POST", data: { "username": "ryxiong", "password": 123, "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中发送到服务端 }, success: function (data) { console.log(data); } })
2.通过ajax设置渲染,只能在html页面中使用
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}'} });
注意:要放在ajax请求的前面,在发送之前组装一组字符串,在第一步render的时候就发送了,所以有局限性:如果把JS代码放到静态文件中,并不会渲染,不会执行{{csrf_token}},只能在HTML页面中使用。
3.手动封装数据头
通过获取返回的cookie中的字符串,放在请求头中发送。
注意:需要引入jquery.cookie.js插件
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script> $.ajax({ headers:{"X-CSRFToken":$.cookie('csrftoken')}, // 其实在ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加 });
六、jQuery和DJango中序列化
1.jQuery.serializer()序列化
serialize()函数用于序列化一组表单元素,将表单内容编码为用于提交的字符串。
-
serialize()函数常用于将表单内容序列化,以便用于AJAX提交。
该函数主要根据用于提交的有效表单控件的name和value,将它们拼接为一个可直接用于表单提交的文本字符串,该字符串已经过标准的URL编码处理(字符集编码为UTF-8)。
无效的表单控件不会被提交,包括:
-
不在<form>标签内的表单控件不会被提交
-
没有name属性的表单控件不会被提交
-
带有disabled属性的表单控件不会被提交
-
没有被选中的表单控件不会被提交
语法
jQueryObject.serialize()
serialize()函数的返回值为String类型,返回将表单元素编码后的可用于表单提交的文本字符串。
html初始代码
<form name="myForm" action="http://www.365mini.com" method="post"> <input name="uid" type="hidden" value="1" /> <input name="username" type="text" value="张三" /> <input name="password" type="text" value="123456" /> <select name="grade" id="grade"> <option value="1">一年级</option> <option value="2">二年级</option> <option value="3" selected="selected">三年级</option> <option value="4">四年级</option> <option value="5">五年级</option> <option value="6">六年级</option> </select> <input name="sex" type="radio" checked="checked" value="1" />男 <input name="sex" type="radio" value="0" />女 <input name="hobby" type="checkbox" checked="checked" value="1" />游泳 <input name="hobby" type="checkbox" checked="checked" value="2" />跑步 <input name="hobby" type="checkbox" value="3" />羽毛球 <input name="btn" id="btn" type="button" value="点击" /> </form>
-
序列化form表单中的所有元素
alert( $("form").serialize()); // 序列化结果: uid=1&username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&sex=1&hobby=1&hobby=2
-
序列化部分表单元素
alert( $(":text, select, :checkbox").serialize()); // 序列化后的结果:username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&hobby=1&hobby=2
使用实例
html文件
<!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"> <title>Title</title> </head> <body> <form name="myForm" action="http://www.365mini.com" method="post"> <input name="uid" type="hidden" value="1" /> <input name="username" type="text" value="张三" /> <input name="password" type="text" value="123456" /> <select name="grade" id="grade"> <option value="1">一年级</option> <option value="2">二年级</option> <option value="3" selected="selected">三年级</option> <option value="4">四年级</option> <option value="5">五年级</option> <option value="6">六年级</option> </select> <input name="sex" type="radio" checked="checked" value="1" />男 <input name="sex" type="radio" value="0" />女 <input name="hobby" type="checkbox" checked="checked" value="1" />游泳 <input name="hobby" type="checkbox" checked="checked" value="2" />跑步 <input name="hobby" type="checkbox" value="3" />羽毛球 <input name="btn" id="btn" type="button" value="点击" /> </form> <script src="/static/jquery-3.2.1.min.js"></script> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script> $("#btn").click(function () { {# 方式一#} //$.ajaxSetup({ // data:{csrfmiddlewaretoken:'{{ csrf_token }}'} //}); $.ajax({ url:"/serialize/", type:"POST", {# 方式三#} headers:{"X-CSRFToken":$.cookie('csrftoken')}, //data:$("form").serialize(), //序列form表单所有的 data:$(":text,:password,:checkbox").serialize(), //序列自己选择的 success:function (data) { var data=JSON.parse(data); //js中的反序列化 console.log(data); console.log(typeof data); $(".error").html(data); } }) }) </script> </body> </html>
views.py
def serialize(request): # form = request.POST # print(form) name = request.POST.get("username") password = request.POST.get("password") checked = request.POST.getlist("hobby") print(name,password,checked) return HttpResponse(json.dumps(name))
当有好多input的时候,就得一一对应的吧所有的数据发过去的,这样显得麻烦,我们用序列化。
// 前端 data:$("form").serialize(), //序列form表单所有的 data:$(":text,:password,:checkbox").serialize(), //序列自己选择的
在服务端获取数据
form = request.POST print(form) #获取所有 name = request.POST.get("username") password = request.POST.get("password") checked = request.POST.getlist("hobby") print(name,password,checked)#获取单个
2.Django内置的serializers
django中内置的serializers可以models中查到的QuerySet对象序列化为json格式,返回给前端,前端通过JSON.parse()方法可以获取
def books_json(request): book_list = models.Book.objects.all()[0:2] from django.core import serializers ret = serializers.serialize("json", book_list) # [{"model": "app01.book", "pk": 1, "fields": {"title": "jinpingmei", "price": 200}}, {"model": "app01.book", "pk": 2, "fields": {"title": "xiaoheishi", "price": 1}}] return HttpResponse(ret)
book_objs = models.Book.objects.all().values('title','price') books = list(book_objs) print(books) # [{'title': 'jinpingmei', 'price': 200}, {'title': 'xiaoheishi', 'price': 1}]
关于json序列化中的注意点
原始json序列化是无法直接序列化python中的事件对象的(datetime, date),如果需要序列化时间对象,需要使用一个类;
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) dt = datetime.now() d = json.dumps(d1,cls=JsonCustomEncoder) # 指定序列化的类 print(d)
这个类的本质就是判断了需要序列化的对象的类型,如果是datetime或者date类型,将他们字符串格式化成了字符串时间,这样json就能够正常序列化。
七、Ajax文件上传
1.请求头ContentType详解
ContentType指的是请求体的编码类型,常见有3种:
application/x-www-form-urlencoded
最常见的 POST 提交数据的方式。
浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。
application/x-www-form-urlencoded方式会将数据封装成类似如下格式发送;
POST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 user=yuan&age=22 // 这就是上面这种contenttype规定的数据格式,后端对应这个格式来解析获取数据,不管是get方法还是post方法,都是这样拼接数据
multipart/form-data
这也是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 属性等于 multipart/form-data。
form表单不支持发json类型的contenttype格式的数据,而ajax什么格式都可以发,也是ajax应用广泛的一个原因。
注意:multipart/form-data上传数据是分段的,一段64kb。
<h1>form上传文件</h1> <form action="{% url 'upload' %}" method="post" enctype="multipart/form-data"> <!--上传文件必须指定enctype属性为multipart/form-data--> {% csrf_token %} <!--csrf认证机制--> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> 头像:<input type="file" name="portrait"> <input type="submit"> </form>
application/json
application/json的数据提交方式,是告诉服务器消息主体是序列化后的json字符串,json规范的广泛流行,使用json发送数据基本不会出现问题。
<h1>ajax上传文件</h1> {% csrf_token %} 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="button" id="upload" value="提交"> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> $("#upload").click(function(){ var username = $("[name=username]").val(); var password = $("[name=password]").val(); $.ajax({ url:"{% url 'upload' %}", // 反向解析请求路径 type:'post', contentType:"json", // 指定发送数据为json格式 data:JSON.stringify({ // 序列化数据为json格式 username:username, password:password, csrfmiddlewaretoken:$("[name=csfrmiddlewaretoken]"), }), success:function (response) { console.log(response) } }) }) </script>
服务端视图函数
def upload(request): """ 处理contentTpye为json的请求数据 :param request: :return: """ if request.method=="GET": return render(request, "upload.html") else: print(request.GET) # <QueryDict: {}> print(request.POST) # <QueryDict: {}> print(request.body) # b'{"username":"ryxiong","password":"ryxiong",...} return HttpResponse("ok")
注意:通过contentType=json提交数据后,数据不存在GET/POST中,而是在请求体的body中。
而且django没有帮我们自动解析json数据,需要我们自己去解析这些数据,
2.基于form表单的文件上传
模板部分upload.html
<h1>form上传文件</h1> <form action="{% url 'upload' %}" method="post" enctype="multipart/form-data"> <!--上传文件必须指定类型--> {% csrf_token %} <!--csrf认证机制--> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> 头像:<input type="file" name="portrait"> <input type="submit"> </form>
视图部分views.py
def upload(request): """ 处理form上传文件的函数 :param request: :return: """ if request.method=="GET": return render(request, "upload.html") else: print(request.POST) # post中没有文件的信息 username = request.POST.get('username') password = request.POST.get('password') file_obj = request.FILES.get("portrait") # 获取文件对象 print(file_obj,type(file_obj)) # 一个文件句柄 吃冰淇淋的小女孩.jpg <class 'django.core.files.uploadedfile.TemporaryUploadedFile'> filepath = os.path.join(settings.BASE_DIR,'statics','img',file_obj.name) with open(filepath,'wb') as f: for chunk in file_obj.chunks(): # chunks()方法,每次取固定大小64kb f.write(chunk) return HttpResponse("ok")
3.基于ajax上传文件
FormData是什么呢?
XMLHttpRequest Level 2添加了一个新的接口FormData.利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单"。
比起普通的ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件.
所有主流浏览器的较新版本都已经支持这个对象了,比如Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+。
注意:通过input文件标签id=upload_file拿到的对象如下
$("#upload_file") // 拿到的是一个集合 $("#upload_file")[0] // 就是一个dom对象 $("#upload_file")[0].files // 拿到的是一个filelist $("#upload_file")[0].files[0] // 拿到的是当前最近的文件对象
注意:要是使用FormData一定要加上
-
contentType:false // 不指定内容格式,按原始数据发送
-
processDate:false // 数据不做预处理
如果不加上,在前端会报错,Illegal innovation的异常。
使用实例
使用ajax上传文件,就不需要通过form表单来提交数据了,之前form表单支持的数据提交格式没有json,ajax就可以以任何数据格式提交。
1.模板文件upload.html,手动组合csrf键值对发送
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>ajax上传文件</h1> {% csrf_token %} 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> 头像:<input type="file" name="file_obj"> <input type="button" id="upload" value="提交"> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> $("#upload").click(function(){ var formdata = new FormData(); // ajax传送文件需要通过FormData的实例来携带传送, var username = $("[name=username]").val(); var password = $("[name=password]").val(); var file_obj = $("[name=file_obj]")[0].files[0]; // 注意先转换成DOM对象,才能调用files方法,获得是一个文件的列表,通过索引取值 var csrf_data = $('[name=csrfmiddlewaretoken]').val(); // formdata对象携带数据方法:append formdata.append('username',username); formdata.append('password',password); formdata.append('file_obj',file_obj); // =========手动封装csrf键值对发送============ formdata.append('csrfmiddlewaretoken',csrf_data); $.ajax({ url:"{% url 'upload' %}", type:'post', data:formdata, processData:false, // 不处理数据,按原始数据发送 contentType:false, // 不设置内容类型,就是不进行编码 success:function (response) { console.log(response) } }); }) </script> </body> </html>
2.模板文件另一种模式,请求头中封装csrf_token
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>ajax上传文件</h1> {% csrf_token %} 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> 头像:<input type="file" name="file_obj"> <input type="button" id="upload" value="提交"> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script> <!--引入jquery中的cookie.js文件--> <script> $("#upload").click(function(){ var formdata = new FormData(); // ajax传送文件需要通过FormData的实例来携带传送, var username = $("[name=username]").val(); var password = $("[name=password]").val(); var file_obj = $("[name=file_obj]")[0].files[0]; // 注意先转换成DOM对象,才能调用files方法,获得是一个文件的列表,通过索引取值 // formdata对象携带数据方法:append formdata.append('username',username); formdata.append('password',password); formdata.append('file_obj',file_obj); // =========设置请求头csrf认证============ $.ajax({ url:"{% url 'upload' %}", type:'post', data:formdata, processData:false, // 不处理数据,按原始数据发送 contentType:false, // 不设置内容类型,就是不进行编码 headers:{"X-CSRFToken":$.cookie('csrftoken')}, // 头部附带cookie的csrf数据发送 success:function (response) { console.log(response) } }); }) </script> </body> </html>
视图文件views.py
def upload(request): """ 处理ajax上传文件的函数 :param request: :return: """ if request.method=="GET": return render(request, "upload.html") else: file_obj = request.FILES.get("file_obj") # 获取文件对象,键名要与发送的数据键名一直 print(file_obj,type(file_obj)) # 一个文件句柄 吃冰淇淋的小女孩.jpg <class 'django.core.files.uploadedfile.TemporaryUploadedFile'> filepath = os.path.join(settings.BASE_DIR,'statics','img',file_obj.name) with open(filepath,'wb') as f: for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse("ok")