JavaScript和普通的jQuery都是操作Html标签以及css属性,不能发送接收数据,最多也只是.submit(),
实际发送数据还是Form表单,提交到同一个url,后台view获取数据然后return同一个页面
悄悄发送数据到后台进行处理,并返回结果而页面不刷新,只能通过Ajax实现
一、原生Ajax
Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),
Ajax首次出现IE5.5中存在(ActiveX控件)。
1、XmlHttpRequest对象的主要方法:
a. void open(String method,String url,Boolen async)
用于创建请求
参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE... #get方式时,xhr.send(null),数据写在url上
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型) #异步发,不影响任何效果
b. void send(String body) #对比jQuery的data:
用于发送请求
参数:
body: 要发送的数据(字符串类型)
c. void setRequestHeader(String header,String value)
用于设置请求头
参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型)
d. String getAllResponseHeaders()
获取所有响应头
返回值:
响应头数据(字符串类型)
e. String getResponseHeader(String header)
获取响应头中指定header的值
参数:
header: 响应头的key(字符串类型)
返回值:
响应头中指定的header对应的值
f. void abort()
终止请求
2、主要属性,如xhr.xxx来使用,不用加括号
a. Number readyState
状态值(整数)
详细:
0-未初始化,尚未调用open()方法,只创建了xml对象;
1-启动,调用了open()方法,未调用send()方法;
2-发送,已经调用了send()方法,未接收到响应;
3-接收,已经接收到部分响应数据;
4-完成,已经接收到全部响应数据;
b. Function onreadystatechange
当readyState的值改变时自动触发执行其对应的函数(回调函数)
这是一个属性,写在open前也可以,只要在创建xhr之后即可
c. String responseText
服务器返回的数据(字符串类型)
d. XmlDocument responseXML
服务器返回的数据(Xml对象)
e. Number states
状态码(整数),如:200、404... 如return HttpResponse(json.dumps(ret),status=404,reason=‘NOT FOUND‘)
f. String statesText
状态文本(字符串),如:OK、NotFound...
3、示例:
function Ajax1() {
var xhr = getXHR(); #一般创建写法var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){ #状态码改变时自动执行
if (xhr.readyState == 4){ #状态码
var obj = JSON.parse(xhr.responseText); #转化为json对象,可以理解为字典
console.log(obj);
}
};
xhr.open(‘POST‘,‘/ajax_json/‘,true);
//xhr.setRequestHeader(‘k1‘,‘v1‘); #设置请求头,如csrf
xhr.setRequestHeader(‘Content-Type‘,‘application/x-www-form-urlencoded; charset-UTF-8‘);
#POST必须按照格式设置文件解析请求头,GET不用设置直接发
xhr.send(‘name=root;pwd=123‘); #发送数据
4、浏览器兼容问题:
function getXHR(){
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
二、jQuery Ajax
内部调用原生XmlHttpRequest,一种浏览器对象,低版本IE没有,有替代的对象active object,jQuery可以用这个替代xml
jQuery 2.x 3.x不支持active object,而1.x支持,兼容性好
1、前端写法:
$(‘#ajax_submit‘).click(function () {
$.ajax({ 开始语句
url: "/test_ajax/",提交到哪个url
type: ‘POST‘,提交方式
data: {‘k‘: ‘v‘,‘list‘: [1,2,3,4],‘k3‘: JSON.stringfy({‘k1‘: ‘v‘}))},$(form对象).serilize()
# 字典不能嵌套字典,可以将字典stringfy传过去
traditional:true,# 提交的data中value包括数组时要声明
// dataType:‘JSON‘,# 后台发送的字符串自动转换为json对象,texthtml不作处理,xml能转就转这格式
// data:$(‘#add_form‘).serialize(),封装提交更方便
success: function (data) { 提交成功后执行函数
// JSON.parse(data); #将字符串转为对象,转字符串是stringfy(),对应前端json.dumpsloads
#声明dataType:‘JSON‘后,就不用转换了
if(data == ‘ok‘){
location.reload() # 重新加载
location.href = "某个地址" # 跳转,只能在这跳转,不能在视图函数中redirect
}
else{
alert(data);
}
},
error:function(){
#网络异常,url错误等
}
});
})
此外还有:
$.get(url=‘‘,data={},success=)
$.post() #内部都是调用ajax方法
2、Django序列化与Ajax
通过Ajax发送数据,在返回时,只能返回字符串,故进行序列化
Django发送:
a.HttpResponse返回字符串时,无需序列化与反序列化
HttpResponse(‘ok‘)
b.返回render渲染模板后生成的字符串,也无需序列化与反序列化
user_list = models.UserInfo.objects.all()
return render(request,‘get_data.html‘,{‘user_list‘:user_list})
注:不能return redirect,ajax不受理;而render返回的是渲染好数据的字符串,不用再dumps和parse
c.返回一个普通的字典,定义一个字典用于返回,统一,判断时修改其中的value
ret = {‘status‘:True,‘error‘:None,‘data‘:{}}
return HttpResponse(json.dumps(ret)) #只能返回字符串,用dumps序列化为形式字典
注:python中序列化与反序列化是json.dumpsloads(),JavaScript中是JSON.stringfyparse()
也可以返回JsonResponse(ret) #django内部执行json.dumps(),只能传字典
JsonResponse([],safe=False),列表也可以,需要传safe=False
d.返回的字典中value是对象的QuerySet时,需要先将对象序列化为字符串,再加入字典中
from django.core import serializers
user_list = models.BookType.objects.all()
ret[‘data‘]= serializers.serialize("json",user_list) #前端需要JSON.parse()转为对象列表即可循环,生成标签等
e.字典中value是字典的QuerySet时,list即可,将QuerySet变成python的list
user_list = models.UserInfo.objects.all().values(‘id‘,‘username‘)
return HttpResponse(json.dumps(ret))
g.字典中value是元组的QuerySet时,list即可,将QuerySet变成python的list
user_list = models.UserInfo.objects.all().values_list(‘id‘,‘username‘)
return HttpResponse(json.dumps(ret))
Ajax发送:
a.普通的字典
data: {‘k‘: ‘v‘}
b.字典value有数组时,需要声明
data: {‘k‘: ‘v‘},4]}
traditional:true #声明数组
c.字典value有字典时,需要序列化字典
data: {‘k‘: ‘v‘},‘k3‘: JSON.stringfy({‘k1‘: ‘v‘}))}
d.封装普通表单数据
data: $(form对象).serilize()
f.表单数据有文件时,需要创建FormData对象并声明
var form = new FormData();
form.append(‘avatar_img‘,file_obj);
form.append(‘csrfmiddlewaretoken‘,‘{{ csrf_token }}‘);
$.ajax({
url: ‘/avatar_upload.html‘,
type:‘POST‘,
data: form,
processData: false,// tell jQuery not to process the data #声明1
contentType: false,// tell jQuery not to set contentType #声明2
success: function (arg) { #这里处理回调数据
var obj = JSON.parse(arg);
$(‘#previewImg‘).attr(‘src‘,‘/‘ + obj.data);
}
})
3、CSRF请求头 X-CSRFToken
全局默认的settings中会更新seetings.py配置,其中csrf有默认设置,字段为HTTP_X_CSRFTOKEN=‘‘,HTTP_是django自动
加的前缀,请求头不能包含下划线,这是非法的,后台拿不到数据,X-CSRFTOKEN,官网推荐为X-CSRFToken
方式一:
$.ajax({
...
headers:{‘X-CSRFToken‘:$.cookie(‘csrftoken‘)}
})
方式二:统一配置一次即可,发送前
$.ajaxSetup({
beforeSend:function(xhr,settings){ #xhr为xmlhttprequest对象
xhr.setRequestHeader(‘X-CSRFtoken‘,$.cookie(‘csrftoken‘)) #设置csrf
}
})
4、与Form组件验证的关系
- Ajax提交:验证正确了cleaned_data是一个字典,可以传,但错误信息ErrorDict不是字典,是一个django对象,不能用python的json.dumps序列化。
- 可以as_json化为字典,再as_json化为字符串HttpResponse给浏览器
(常用)- 通过json.dumps定制一个Clis,进行特殊对象的序列化,什么类型取什么值,构造出json对象,返回需要的值
5、与原生Ajax的联系:
$.ajax({
...
success: function (data,a1,a2) { #第一个参数是success,第二个参数为XmlHttpRequest对象,即可调用原生ajax方法写
if(){}
else{}
}
})
三、伪Ajax
1、原理:利用iframe框改src时框跳转,但大页面不刷新,实现不刷新发送请求,而普通的form表单会刷新
兼容性最好
2、iframe标签跳转:
<input type="text" id="url"/>
<input type="button" value="发送" onclick="ifm_request();"/>
<iframe id="ifm" src="http://www.baidu.com"></iframe> #跳转网页
function ifm_request() {
var url = $(‘#url‘).val();
// console.log(url)
$(‘#ifm‘).attr(‘src‘,url);
}
因此,利用iframe实现伪ajax方法,不依赖任何插件
3、iframe实现发送和接收数据
<form action="/ajax_json/" method="post" target="ifm1"> #target属性让form和iframe建立关系,表单数据通过iframe发送
<iframe id=‘ifm1‘ name="ifm1"></iframe> #iframe框,可写在表单外
<input type="text" name="username" />
<input type="text" name="email" />
<input type="submit" onclick="submitForm();" value="提交"/>
</form>
写一个js,当点击提交时,获取发送的数据:
function submitForm() {
$(‘#ifm1‘).load(function () {
var text = $(‘#ifm1‘).contents().find(‘body‘).text(); #contents是整个html,找到body标签
var obj = JSON.parse(text); #text是字符串
})
}
4.iframe标签的内容:
iframe标签包含的是document对象,相当于上下文,或者空间管理,嵌套了html,innerText、children等无法使用
对象里面有html标签-headerbody标签,body标签的文本即返回的字符串
Jquery方式:
通过.contents()拿到html对象
$(‘#ifm1‘).contents().find(‘body‘).text()html():文本内容
DOM方式:
.contentWindow:拿到嵌套的document
.contentWindow.document.body:拿到body内容
.contentWindow.document.body.innerHtml:拿到body文本内容
5.iframe接收数据的时机: form提交后,要等到服务器返回数据时iframe框才接收到数据,同时触发onload事件,在jQuery为$().load() 由于从上到下加载时先给iframe绑定load事件会报错,可以点submit时再绑定load 6.上传文件图片以及预览 view函数中 username = request.POST.get(‘username‘) fafafa = request.FILES.get(‘fafafa‘) #获取文件,可chunks()写入 img_path = os.path.join(‘static/imgs/‘,fafafa.name) with open(img_path,‘wb‘) as f: for item in fafafa.chunks(): f.write(item) ret = {‘status‘:True,‘data‘:img_path} #返回文件路径,用于预览 return HttpResponse(json.dumps(ret)) 前端 function ifmSubmit() { $(‘#ifm1‘).load(function () { var text = $(‘#ifm1‘).contents().find(‘body‘).text(); var obj = JSON.parse(text); $(‘#preview‘).empty(); #先清空 var imgTag = document.createElement(‘img‘); #创建标签,也可以创建好一个img标签,直接赋值src即可 imgTag.src = "/"+obj.data; #路径要以/开头,这是静态路径,添加到src即可查看 $(‘#preview‘).append(imgTag); #添加内容 }) } 对比jQuery: success: function (arg) { var obj = JSON.parse(arg); #对比iframe,这里return的数据直接拿到,arg即ret if(obj.status){ $(‘#previewImg‘).attr(‘src‘,‘/‘ + obj.data); #不同于上面的创建标签,这里是直接对img标签操作 } } 对比原生Ajax: xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ var obj = JSON.parse(xhr.responseText); #拿到 $(‘#previewImg‘).attr(‘src‘,‘/‘ + obj.data); } }; 三个的不同在于返回数据的获取,标签src都要使用jQuery,也可以dom ====================================ajax操作时机=============================== 如果发送的是普通的数据、字符串 ------> jQuery,XMLHttpRequest,iframe 如果发送的是文件 ------> iframe,jQuery(FormData),XMLHttpRequest(FormData)===============================================================================