一、json回顾
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 格式。
JSON 格式有两个显著的优点:
- 书写简单,一目了然;
- 符合 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)。
无效的表单控件不会被提交,包括:
- 不在标签内的表单控件不会被提交
- 没有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)
但是这样序列化后的数据并不清晰,也不太好取,所以一般推荐下面方式获取models数据
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 提交数据的方式。
浏览器的原生 表单,如果不设置 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 数据提交的方式。我们使用表单上传文件时,必须让 表单的 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")