python-Django与ajax实现前后端交互, 局部刷新
**一 什么是Ajax **
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
这样就不用对整个网页进行刷新, 即可更新数据.
使用场景:
用户注册或选项中
实时验证
优点:
- ajax使用JavaScript技术向服务器发送异步请求
- 无需刷新页面即可得到更好的提示效果
那么是怎么实现的呢
基于jquery的ajax实现前后端交互
先简单的实现一个交互
这里只写前端js代码, 后续补上全部代码
<script src="/static/jQuery/jQuery.min.js"></script>
<script>
$("#btn").click(function () {
$.ajax({
url:"/提交地址/",
method:'post', //以post方法提交
data:{ //携带数据
username:"用户名",
password:"密码"
},
success:function (data) { // 正确返回结果
console.log(data) // 打印到控制台
},
error:function (data) { // 请求不到数据或数据不存在返回结果
console.log(data)
}
})
})
</script>
ajax执行流程
完整案例
实现一个局部向服务器提交数据,得到结果后动态局部填充
代码实现如下
简单的请求响应, # GET 请求返回静态界面, # 判断是否为ajax请求, 不是返回请求无效
view视图
from django.shortcuts import render
from django.http import JsonResponse
def test_ajax(request):
#
if request.method == "GET":
return render(request, 'index.html')
res = {"code": 101, "msg": "请求无效"}
#
if request.is_ajax():
rest = request.POST
s1 = int(rest.get("con1"))
s2 = int(rest.get("con2"))
s3 = s1 + s2
res["msg"] = s3
return JsonResponse(res) // 成功与否都返回json数据格式
路由, 只要一个路由, get,post都走这个
urlpatterns = [
...
path("ajax-add/", views.test_ajax),
]
HTML界面, 这里使用的是 jquery方法,使用前需要导入jquery, 代码中有详细解释, 请 耐心看完
<script src="/static/jQuery/jQuery.min.js"></script>
# 显示输入框,
<div>
<input type="text" id="cont1"> +
<input type="text" id="cont2"> =
<input type="text" readonly id="total">
</div>
<br>
<input type="submit" class="btn-primary" id="sub">
jquery实现代码
<script>
$("#sub").click(function () {
$.ajax({
url:"/ajax-add/", // 请求路由, 向ajax-add地址发送请求
method:"post", // 请求方式, 可以指定多种请求方式, 这里使用post请求
data:{ // 请求携带数据,
con1:$("#cont1").val(), // 根据标签中的id取值
con2:$("#cont2").val()
},
success:function (data) { // 成功后执行该函数, 否则不执行
$("#total").val(data.msg) // 给id为total标签添加请求成功后返回数据
}
})
})
</script>
2 基于ajax进行注册验证
一个简单的ajax请求已经了解, 接下来实现注册时提示功能
用户在表单输入用户名与密码,通过Ajax提交给服务器,服务器验证后返回响应信息,客户端通过响应信息确定是否注册成功,成功,则跳转到登录页面,否则,在页面上显示相应的错误信息
代码如下
视图, 这是就需要两个路由了 , 因为检查用户是否存在和提交真实用户注册数据都是post请求, 需要单独写路由, 如果多一点判断也是可以实现的, 这里就简单的写了
提交信息函数
def register(request):
# GET 请求返回静态界面
if request.method == "GET":
return render(request, 'index.html')
res = {"code": 101, "msg": "请求无效"}
# 判断是否为ajax请求, 不是返回请求无效
if request.is_ajax():
rest = request.POST
// 存储数据
try:
models.User.objects.create(name=rest.get("username"), password=rest.get("password"))
res["code"] = 100
res["msg"] = '注册成功'
except Exception:
res["msg"] = '提交信息有误'
return JsonResponse(res)
检查用户是否存在
def check(request):
res = {"code":101, "msg":"用户名可用"}
username = request.POST.get("username")
user = models.User.objects.filter(name=username).count()
if user:
res["msg"] = '该用户已存在'
return JsonResponse(res)
路由
urlpatterns = [
...
path("register/", views.register),
path("check/", views.check)
]
HTML代码
注: 需要先导入bootstrap.min.css
和 jQuery.min.js
页面显示代码
<div class="center-block">
<div class="form-group">
<label for="bt">账号</label>
<input type="text" class="form-control" placeholder="请输入账号" id="bt">
<span id="count" class="pull-right"></span>
</div>
<div class="form-group">
<label for="bs">密码</label>
<input type="password" class="form-control" placeholder="请输入密码" id="bs">
</div>
<span id="password"></span>
<button type="button" class="btn btn-primary" id="btn">注册</button>
</div>
js代码, 代码分为两段, 一个是检验用户, 单独写, 当鼠标移开input框后发送ajax请求验证数据
有则提示用户已经存在
没有则提示可以注册
<script>
// 鼠标移开input框后提交数据验证
$("#bt").blur(function () {
$.ajax({
url:"/check/",
method:"post",
data:{
username:$("#bt").val(),
},
success:function (data) {
if (data.code === 100){
$("#password").html(data.msg)
// 跳转登录页面
// location.href = '/login/'
}
else {
$("#count").html(data.msg)
}
}
})
})
// 点击后提交真实数据
$("#btn").click(function () {
$.ajax({
url:"/register/",
method:"post",
data:{
username:$("#bt").val(),
password:$("#bs").val()
},
success:function (data) {
$("#password").text(data.msg)
}
})
})
</script>
成功后如图
下面完成最后的ajax提交文件, 前面已经写过篇, 为使用js动态显示头像, 这里是使用 ajax 提交图片或文件数据到后台
文件上传
请求头ContentType
1 application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 表单,如果不设置 enctype
属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):
后续的HTML页面就不粘贴到这里了, 都是根据id取值, 懂得都懂
POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
user=lqz&age=22
2 multipart/form-data
这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 表单的 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 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 表单也只支持这两种方式(通过 元素的 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上传文件
$("#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格式数据
$("#ajax_test").click(function () {
var dic={'name':'lqz','age':18}
$.ajax({
url:'',
type:'post',
contentType:'application/json', //一定要指定格式 contentType: 'application/json;charset=utf-8',
data:JSON.stringify(dic), //转换成json字符串格式
success:function (data) {
console.log(data)
}
})
})
提交到服务器的数据都在 request.body 里,取出来自行处理
六 Django内置的serializers(把对象序列化成json字符串)
from django.core import serializers
def test(request):
book_list = Book.objects.all()
ret = serializers.serialize("json", book_list)
return HttpResponse(ret)
//转换成json字符串格式
success:function (data) {
console.log(data)
}
})
})
提交到服务器的数据都在 request.body 里,取出来自行处理
六 Django内置的serializers(把对象序列化成json字符串)
from django.core import serializers
def test(request):
book_list = Book.objects.all()
ret = serializers.serialize("json", book_list)
return HttpResponse(ret)