Django与ajax详细
目录
ajax----->服务器------>ajaxkedudaun
七、Django内置的serializers(把对象序列化成json字符串)
一、什么是Ajax
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
-
同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
-
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
具体应用场景:
比如我们在某个网站注册账户的时候, 我们已输入就会有提示, 我们的输入是否合法, 是否重复, 但是在输入之前是没有的, 这运用的就是ajax进行处理的
优点:
-
AJAX使用Javascript技术向服务器发送异步请求
-
AJAX无须刷新整个页面
二 基于jquery的Ajax实现
<button class="send_Ajax">send_Ajax</button> <script> // 使用jquery 设置点击事件发送ajax请求 $(".send_Ajax").click(function(){ $.ajax({ // 在里面进传入相应的参数 // 可以请求ajax请求的服务端地址 url:"/handle_Ajax/", // 发送请求的方式, 类型 type:"POST", // 向后台发送数的数据字典 data:{username:"Yuan",password:123}, // 后台响应成功的数据接收 success:function(data){ console.log(data) }, // 错误信息的接收和处理 error: function (jqXHR, textStatus, err) { console.log(arguments); }, // 请求完成后的动作处理 complete: function (jqXHR, textStatus) { console.log(textStatus); }, // 状态码的处理 statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); }, '400': function (jqXHR, textStatus, err) { console.log(arguments); } } }) }) </script>
ajax----->服务器------>ajaxkedudaun
三 案例
案例一、 通过Ajax,实现前端输入两个数字,服务器做加法,返回到前端页面
在Django的 views中写上处理ajax请求的视图响应函数
-
def test_ajax(requests): n1=int(requests.POST.get('n1')) n2=int(requests.POST.get('n2')) return HttpResponse(n1+n2)
在前端 前端中的js代码, 其中的步骤和上面的一样
使用jquery做一个点击事件来发送全国的csvn $("#submit").click(function () { $.ajax({ url: '/test_ajax/', type: 'post', data: { n1: $("#num1").val(), n2: $("#num2").val() }, success: function (data) { console.log(data) $("#sum").val(data) }, }) })
在html中的代码
<input type="text" id="num1">+<input type="text" id="num2">=<input type="text" id="sum"> <button id="submit">计算</button>
案例二 基于Ajax进行登录验证
用户在表单输入用户名与密码,通过Ajax提交给服务器,服务器验证后返回响应信息,客户端通过响应信息确定是否登录成功,成功,则跳转到首页,否则,在页面上显示相应的错误信息
首先定义好视图响应函数:
定义视图响应函数的时候, 要先和前台沟通好数据格式, 发送数据的格式, 路由的设置等等一系列问题
def auth(request): # 设置一个字典 back_dic={'user':None,'message':None} # 根据后台发送数据的方式获取我们需要的信息 name=request.POST.get('user') password=request.POST.get('password') print(name) print(password) # 根据获取到的信息和从数据库中拿出来的信息进行比对,得到最终结果然后返回给前台 user=models.user.objects.filter(name=name,password=password).first() print(user) # print(user.query) # 可以打印出来查信息的sql语句 # 这里我们只做了简单的校验 if user: back_dic['user']=user.name back_dic['message']='成功' else: back_dic['message']='用户名或密码错误' import json # 使用json 返回给前台一个json格式的数据 return HttpResponse(json.dumps(back_dic))
前端写在script标签中的js代码, 用来发送 ajax请求
<script> $("#submit3").click(function () { $.ajax({ url: '/auth/', type: 'post', data: { 'user': $("#id_name").val(), 'password': $('#id_password').val() }, success: function (data) { {#console.log(data)#} var data=JSON.parse(data) if (data.user){ location.href='https://www.baidu.com' }else { $(".error").html(data.message).css({'color':'red','margin-left':'20px'}) } } }) } )</script>
traditional:true--->可以序列化一层列表,多层不行,要转成json格式上传
四 文件上传
请求头ContentType
1 application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype
属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):
POST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 user=onion&age=22
以第一种Content Type格式发送数据的时候, 或者如果不指定编码格式,不管是form表单还是ajax传送数据时默认的编码就是unlencode,会把data这个字典转成 key1=value1&key2=valeu2 这种方式,放到request的body体里面, 然后Django会对这种格式的数据做处理, 放到POST的字典里面, 所以在视图响应函数中直接使用request.POST.get()来获取到这种方式进行数据交互
2 multipart/form-data
这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype
等于 multipart/form-data。直接来看一个请求示例:
POST http://www.example.com HTTP/1.1 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="user" yuan ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="file"; filename="chrome.png" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
这个例子稍微复杂点。首先生成了一个 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
application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。当需要提交的数据层次非常深的时候,就可以把数据 JSON 序列化之后再进行提交。也可以把 JSON 字符串作为 val,仍然放在键值对里,以 x-www-form-urlencoded 方式提交。
基于Form表单上传文件
<form action="/file_put/" method="post" enctype="multipart/form-data"> 用户名:<input type="text" name="name"> 头像:<input type="file" name="avatar" id="avatar1"> <input type="submit" value="提交"> </form>
必须指定 enctype="multipart/form-data"
视图函数:
def file_put(request): if request.method=='GET': return render(request,'file_put.html') else: # print(request.POST) # print(request.POST) print(request.body) # 原始的请求体数据 print(request.GET) # GET请求数据 print(request.POST) # POST请求数据 print(request.FILES) # 上传的文件数据 # print(request.body.decode('utf-8')) print(request.body.decode('utf-8')) print(request.FILES) file_obj=request.FILES.get('avatar') print(type(file_obj)) with open(file_obj.name,'wb') as f: for line in file_obj: f.write(line) return HttpResponse('ok')
基于Ajax上传文件
processData:false, //告诉jQuery不要去处理发送的数据
contentType:false, // 告诉jQuery不要去设置Content-Type请求头
$("#ajax_button").click(function () { var formdata=new FormData() formdata.append('name',$("#id_name2").val()) formdata.append('avatar',$("#avatar2")[0].files[0]) $.ajax({ url:'', type:'post', processData:false, //告诉jQuery不要去处理发送的数据 contentType:false,// 告诉jQuery不要去设置Content-Type请求头 data:formdata, success:function (data) { console.log(data) } }) })
浏览器请求头为:
Content-Type:
multipart/form-data; boundary=----WebKitFormBoundaryA5O53SvUXJaF11O2
五 Ajax提交json格式数据的几种方式
在前端提交json格式数据的时候要注意前端发送数据到服务器的时候,服务器对不同编码格式的数据不同的处理方式:
在前端编码格式对服务器处理数据时的影响:
-
发送的数据只要是urlencoded编码: Http请求的body体中的数据格式为:key1=value1&key2=valeu2
-
指定编码格式为json格式:Http请求的body体中的数据格式为:"{"key1":"value1","key2":"valeu2"}",数据到后端需要自己处理
-
提交到服务器的数据都在 request.body 里,取出来自行处理
指定格式的时候还可以指定编码的格式:
contentType: 'application/json;charset=utf-8' ,
指定发送给后台的数据格式使用contentType来指定, 指定接收后台数据的格式通过datatype来指定:
指定接收后台传回来的数据为json格式时, 如果传回来的数据不是json格式的时候, 在前端的数据解析就会出现问题, 数据就不会正常渲染到页面中,
$("#btn").click(function () { var dic ={'name': $("#name").val(),'pwd':$("#pwd").val()} $.ajax({ url: '/file/', type: 'post', dataType:'json', // 指定接收后台传回来的数据是json格式的数据时,才会正常解析 data:dic, success: function (data) { alert(data.name) } }) })
方式一:
在ajax请求中,定义一个字典, 并指定发送数据的格式为json, 并且还需要使用JSON.stringify()来将定义的字典转换成json字符串格式进行发送.,这样在Django服务器的request.body总会接收到一个json格式的字符串,只有body体中有数据, Django不会将数据进行处理放进POST或者GET字典中, 这个时候导入json模块进行反序列化(json.load(request.bady))即可将其转换为字典类型, 然后就可以当做一般的字典使用了.
$("#ajax_test").click(function () { var dic={'name':'eric','age':18} $.ajax({ url:'', type:'post', contentType:'application/json', //一定要指定格式 data:JSON.stringify(dic), //转换成json字符串格式 success:function (data) { console.log(data) } }) })
方式二:
借助于formdata对象, formdata是js中的类FormData实例化出来的, 使用的时候实例化出来对象之后, 直接将要发送给后台的数据使用append方法传进去就可以了, append中的第一个参数是key第二个参数是value, value的值可以是输入框的值,也可以是一个文件对象或者, 该对象会将添加入的数据转成json格式, 要注意的是一定要指定processData:false, contentType:false这两个参数为false, 如果不指定ajax会默认进行处理, 使用formdate的对象的好处是将数据发送回后台的时候,和使用form表单发送的http请求时没有区别的, 同时又因为本身是ajax请求, 可以实现异步提交和局部刷新; 在后台可以按照常规方式获取数据进行处理
$("#ajax_button").click(function () { var formdata=new FormData() formdata.append('name',$("#id_name2").val()) formdata.append('avatar',$("#avatar2")[0].files[0]) $.ajax({ url:'', type:'post', processData:false, //告诉jQuery不要去处理发送的数据 contentType:false,// 告诉jQuery不要去设置Content-Type请求头 data:formdata, success:function (data) { console.log(data) } }) })
总结:
如果前端传的格式是json格式,django不会处理body中的内容,需要自己在后台取出来之后进行处理
只有前端传的格式是urlencoded,或者form-data格式,django才会给处理,处理方式是从body体中取出来放到POST或者GET字典中, 然后在后台根据对应的请求方式进行取值就可以了
六、在Django中返回给前端json格式数据的几种方式
在views中接收到请求, 并经过对数据进行逻辑处理之后,返回给前端的时候, 想要返回一个json格式的数据的方式:
方式一:
利用Django中的JsonResponse
利用这种方式返回数据的时候,在前端接收到的数据就是一个object对象, 也就是我们说的字典对象, 可以在前端直接使用点语法进行取值使用, 原理就是在使用JsonResponse返回数据的时候, JsonResponse在响应头中指定了contentType为'application/json', 在ajax收到数据的时候, 就会根据这个响应头将后天返回的数据进行处理, 处理成一个object对象供自己使用
from django.http import JsonResponse def login(request): dic={'status':100,'msg':None} if request.method == 'GET': return render(request, 'login.html') # if request.is_ajax(): if request.method=='POST': name=request.POST.get('name') pwd=request.POST.get('pwd') if name=='lqz' and pwd=='123': dic['msg'] = '登陆成功' # 想让前端跳转 # dic['url']='http://www.baidu.com' dic['url']='/test/' else: # 返回json格式字符串 dic['status']=101 dic['msg']='用户名或密码错误' return JsonResponse(dic)
方式二:
使用json模块直接返回一个json格式的字符串, 这种方式在前端ajax接收到响应之后,不会进行转换, 因为在后台我们只是将数据序列化了一下, 返回的实质上还是HttpResponse回去一个字符串, 只不过格式是json格式的, 要想在前端想字典一样使用, 需要在前端使用JSON.parse()进行处理, 处理过后数据就变成了一个object, 就可以按照点语法在前端正常使用了.
import json from django.http import JsonResponse def login(request): dic={'status':100,'msg':None} if request.method == 'GET': return render(request, 'login.html') # if request.is_ajax(): if request.method=='POST': name=request.POST.get('name') pwd=request.POST.get('pwd') if name=='eric' and pwd=='123': dic['msg'] = '登陆成功' # 想让前端跳转 # dic['url']='http://www.baidu.com' dic['url']='/test/' else: # 返回json格式字符串 dic['status']=101 dic['msg']='用户名或密码错误' return HttpResponse(json.dumps(dic))
总结:
1 后端如果返回JsonResponse,前端的ajax内部会自动将json格式字符串转换成字典
2 后端如果返回HttpResponse,前端的ajax内部不会给你自动转换,拿到的data是字符串类型,需要手动JSON.parse(data)来转成字典
七、Django内置的serializers(把对象序列化成json字符串)
from django.core import serializers from django.core import serializers def test(request): book_list = Book.objects.all() ret = serializers.serialize("json", book_list) return HttpResponse(ret) # 如果不想序列化某些字段, 可以只返回时指定fields, 例如: data = serializers.serialize('json', users, fields=('username', 'id'))