共计 9533 个字符,预计需要花费 24 分钟才能阅读完成。
一.Ajax 简介
1. 什么是 Ajax
- AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步 Javascript 和 XML”
- 即使用 Javascript 语言与服务器进行异步交互,传输的数据为 XML
- 当然,传输的数据不只是 XML,现在更多使用 json 数据
- 通俗的讲 : 它是一种创建交互式网页应用的网页开发技术
2.Ajax 特点
- 异步提交
- 浏览器页面 局部刷新 : 这一特点给用户的感受是在不知不觉中完成请求和响应过程
3. 异步与同步提交
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求
4. 前端向后端发起请求方式
- 地址栏输入 url 回车 : GET
- a 标签 href 属性指定的 url : GET
- form 表单中的 submit 与 button 类型 : GET/POST
- ajax 请求 : GET/POST
- 注意 : 如果不想触发 form 表单提交, 1. 按钮可以不写在 form 表单中,2. 使用 input, 类型为 button
ps : 原生 js 写的 ajax 非常麻烦, 需要兼容多种浏览器, 并且企业也基本不会用, 下面的学习我们只基于 jQuery 的 Ajax 实现, 并不只有 jQuery 能够实现 ajax,其他的框架也可以 但是换汤不换药, 原理是一样的
二.Ajax 入门小示例
1. 需求
- 页面三个输入框和一个 ''计算'' 按钮
- 在前两个输入框内输入数字, 点击计算按钮, 在第三个输入框内动态展示前两数字乘积
- 使用 Ajax 向后端提交请求, 页面不能进行刷新
- 计算必须在后端进行
2. 代码示例
- 路由层 urls.py 文件
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [path('admin/', admin.site.urls),
re_path('^ajax/', views.ajax_test),
re_path('^pro/', views.product),
]
- 视图层 views.py 文件
def ajax_test(request):
return render(request,'ajax.html')
def product(request):
if request.method == "POST":
a1 = request.POST.get('a1')
a2 = request.POST.get('a2')
a = int(a1)*int(a2)
return HttpResponse(a)
- 模板层 ajax.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'jquery-3.4.1/jquery.min.js' %}"></script>
<link href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="stylesheet">
<script src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script>
</head>
<body>
<input type="number" class="form-control text-center" id="a1">
<p class="text-center">x</p>
<input type="number" class="form-control text-center" id="a2">
<p class="text-center">=</p>
<input type="number" class="form-control text-center" id="a3">
<button class="btn btn-warning btn-block"> 计算 </button>
<script>
// 设置点击事件
$('.btn').click(function (){
// 朝后端发送 ajax 请求
$.ajax({
// 指定后端地址, 不指定则提交到当前地址
url:'/pro/',
// 指定请求方式, 不指定默认 get
method:'post',
// 需要发送的数据
data:{'a1':$('#a1').val(),'a2':$('#a2').val()},
// 回调函数: 后端返回结果的时候自动触发, 并将结果传给 args
success:function(args){
// 通过 DOM 操作渲染到第三个 input 内
$('#a3').val(args)
}
})
})
</script>
</body>
</html>
3. 展示效果
三. 登入验证示例
1.form 表单提交与 ajax 提交
前面我们说到 ajax 的提交会与 form 表单的提交先后进行, 也就是进行了两次提交, 这显然不是我们想看到的结果, 解决方法有两种:
- 将 submit 或 button 按钮放在 form 表单外面(上面的例子我们是直接没有写 form 表单)
- 使用 input 输入框 +type='button' 来替代按钮, 这样就无法触发 form 表单的提交(下面这个示例我们使用这种)
2. 需求
- 用户输入用户名和密码, 点击登入朝后端进行提交
- 后端从数据库拿到数据进行校验, 返回状态码和登入信息
- 登入成功通过前端进行跳转网站 http://124.71.206.179:8000
- 登入失败显示错误提示信息
- 使用 ajax 向后端提交请求
ps :
request.is_ajax()
判断是否是 Ajax 请求
3. 实现代码
- 路由层 urls.py 文件
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [path('admin/', admin.site.urls),
re_path('^login/', views.login),
]
- 模型层 models.py 文件
from django.db import models
class User(models.Model):
name = models.CharField(max_length=16,verbose_name='用户名')
pwd = models.CharField(max_length=16,verbose_name='密码')
def __str__(self):
return self.name
- 用户数据
- 视图层 views.py 文件
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
from django.http import JsonResponse
def login(request):
dic = {'status':None,'msg':None} # 设置 dic 保存状态码及登入状态信息
# 如果是 ajax 请求
if request.is_ajax():
name = request.POST.get('name') # 获取用户名
pwd = request.POST.get('pwd') # 获取密码
user_obj = models.User.objects.filter(name=name,pwd=pwd).first() # 拿到对象
if user_obj:
dic['status'] = 200 # 存在状态码设置成 200
else:
dic['status'] = 201
dic['msg'] = '用户名或密码错误'
# 方式一 : 直接使用 JsonResponse
return JsonResponse(dic) # 将登入状态 dic 返回给前端 ajax
# 方式二 : 手动转 json 格式
# import json
# return HttpResponse(json.dumps(dic))
return render(request,'login.html') # get 请求展示 login 页面
上面可以使用方式一和方式二向后端返回响应 :
- 方式一返回的是 json 格式, 那么 ajax 接收到数据后会自动转成对象, 然后前端直接可以拿对象进行操作
- 方式二是以字符串的方式返回了 json 格式的字符串(html/text 格式), ajax 接收后需要我们自己去反序列化成对象
- 总结 : 后端返回数据我们统一使用 JsonResponse 就可以了
ps : 如果使用了 ajax, 后端就不要再使用 redirect、render、HttpResponse 了, 直接使用 JsonReponse
- 模板层 login.html 文件
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-info">
<div class="panel-heading"> 用户登入 </div>
<div class="panel-body">
<form action="">
用户名:
<input type="text" class="form-control" id="a1">
密码:
<input type="password" class="form-control" id="a2">
<br>
<input type="button" class="btn btn-warning btn-block" value=" 登入 ">
<p class="aa" style="color: red"></p>{# 设置一个标签用来展示用户登入状态信息 #}
</form>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
$('.btn').click(function () {
$.ajax({
url:'/login/',
method:'post',
data:{'name':$('#a1').val(),'pwd':$('#a2').val()},
success:function (data) {
// 方式二 : 加一行, 将 json 格式字符串转成字典
// data = JSON.parse(data)
// 状态码为 200 则表示登入成功
if (data.status === 200){
// 前端进行网页跳转
location.href='http://124.71.206.179:8000'
}else {
// 登入失败则使用 DOM 操作渲染 msg
$('.aa').html(data.msg)
}
}
})
})
</script>
3. 效果展示
- 校验失败渲染 msg
- 校验成功跳转
四. 前后端数据传输的编码格式
1. 前端中可以向后端发起 post 请求的方式
- form 表单
- ajax 请求
2. 基于 post 请求, 前后端数据传输的主流编码格式有三种
- urlencoded : 默认的编码格式, 提交的数据从
request.POST
中提取 - form-data : 上传文件时使用的编码格式, 提交的数据从
request.POST
中提取, 上传的文件从request.FILES
中提取 - json : ajax 发送的 json 格式数据, 在
request.POST
中取不到 数据, 需要在request.body
中提取数据
3. 基于 post 请求, form 表单传输数据默认的编码格式
- 默认编码格式为 : urlencoded
- 如果要上传文件需要在标签中指定 : enctype="multipart/form-data" 编码格式
- 数据格式 : username=shawn&password=1111
- 提交位置 : django 后端针对符合 urlencoded 编码格式的数据都会自动帮你解析封装到 request.POST 中, 文件提交到
request.FILES
中
4. 基于 post 请求, ajax 传输数据默认编码格式
- 默认编码格式 : urlencoded
- 如果要上传文件需要使用 Formdata 对象
- 数据格式 : username=shawn&password=1111
- 提交位置 : django 后端会自动帮你解析封装到 request.POST 中, 文件提交到
request.FILES
中
5.json.loads()是否可以转 Bytes 格式
- 3.5之前不行, 需要我们手动将 Bytes 格式转成 str 类型, 然后再进行转换
- 3.6以后可以, Bytes 无需手动转 str 类型, 它内部会自动帮你转成 str, 再转成 json
- 查看
json.loads()
的源码可以得到验证 :
五. 基于 form 表单上传文件
1. 代码实现
- 路由层 urls.py 文件
re_path('^files/', views.files),
- 视图层 views.py 文件
def files(request):
if request.method == 'POST':
remark = request.POST.get('remark')
myfile = request.FILES.get('files')
print(remark) # hello
print(myfile) # 11.png
print(type(myfile)) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
with open(myfile,'wb')as f:
for line in myfile:
f.write(line)
return HttpResponse('上传成功')
return render(request,'files.html')
- 模板层 files.html 文件
<form action="" method="post" enctype="multipart/form-data">
留言 : <input type="text" class="form-control" id="a2" name="remark">
文件 : <input type="file" class="form-control" id="a1" name="myfile">
<br>
<input type="submit" class="btn btn-success btn-block" value=" 提交 ">
</form>
2. 效果展示
六. 基于 ajax 上传文件
1. 储备知识
- 使用 ajax 发送文件对象需要借助于 js 内置对象 FormData
- new 一个 FormData 对象
var FormDataObj = new FormData
- jQuery 表单中获取文件对象
<input type="file" class="form-control" id="file" name="myfile">
$('#file') // jQuery 对象
$('#file')[0] // 拿到原生 js 文件对象集
$('#file')[0].files[0] // 从中取到第一个文件对象
- FormData 对象添加数据方式
.append
语法 : FormDataObj.append([key],[value]) // 支持添加文件
var file = $('#file')[0].files[0]
FormDataObj.append('myfile',file)
- ajax 中参数
// 上传文件必须注意的参数
processData: false, // 不预处理数据,让浏览器不要额外的处理 data 中的数据
contentType: false, // 不指定编码格式,使用 FormDataObj 对象的默认编码就是 formdata 格式
data:FormDataObj, // 指定要发送的数据, 直接放 FormData 对象
2. 代码实现
- 路由层 urls.py 文件
re_path('^ajax_file/', views.ajax_file)
- 视图层 views.py 文件
def ajax_file(request):
if request.is_ajax():
remark = request.POST.get('remark')
myfile = request.FILES.get('myfile')
print(remark) # haha
print(myfile) # 1.jpg
print(type(myfile)) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
with open(myfile.name,'wb')as f:
for line in myfile:
f.write(line)
return HttpResponse('使用 ajax 文件上传成功')
return render(request,'ajax_file.html')
- 模板层 ajax_file.html 文件
// html 标签
<form action="">
留言 : <input type="text" class="form-control" id="a2">
文件 : <input type="file" class="form-control" id="a1">
<br>
<input type="button" class="btn btn-success btn-block" value=" 提交 ">
</form>
// script
<script>
$('.btn').click(function () {var FormDataObj = new FormData() // new 一个 FormData 对象
var remark = $('#a2').val() // 取到 remark 值
var myfile = $('#a1')[0].files[0] // 取到文件对象
FormDataObj.append('remark', remark) // 将 remark 添加到对象中
FormDataObj.append('myfile', myfile) // 将文件对象添加到对象中
$.ajax({
url: '/ajax_file/',
method: 'post',
processData: false,
contentType: false,
data: FormDataObj,
success: function (args) {alert(args)
location.href='/ajax_file/'
}
})
})
</script>
3. 效果展示
七.stringify 与 parse 方法
stringify 和 parse 都是 JavaScript 中关于 JSON 对象和字符串转换的方法:
1.JSON.stringify() 序列化
- 用于将 JavaScript 值转换为 JSON 字符串
res = JSON.stringify({'name':"shawn"})
2.JSON.parse() 反序列化
- 用于将一个 JSON 字符串转换成 JavaScript 对象
- json 只能识别双引号的字符串格式
res = JSON.parse('{"name":"shawn"}')
八.ajax 发送 json 格式数据
提示 : 前端向后端发送数据的时候, 必须要保证数据格式与发送时 contentType 指定的数据格式一致
1. 代码实现
- 路由层 urls.py 文件
re_path('^ajax_json/', views.ajax_json)
- 视图层 views.py 文件
def ajax_json(request):
if request.is_ajax():
# json 格式数据需要到 request.body 中取, 其他里面没有
print(request.POST) # <QueryDict: {}>(空的)
print(request.FILES) # <MultiValueDict: {}>(空的)
print(request.body) # b'{"name":"\xe8\xae\xb8\xe6\x96\x87\xe5\xbc\xba","pwd":"123456"}'
# 3.5Python 解释器以前需要手动将 Bytes 格式转换成 str 格式, 再进行反序列化
# data_bytes = request.body
# data_json_str = data_bytes.decode()
# data_dict = json.loads(data_json_str)
# 3.6 版本以后,json.loads 支持支持反序列化 Bytes 格式(第四小节有源码介绍)
data_dict = json.loads(request.body)
name = data_dict['name']
pwd = data_dict['pwd']
print(name,pwd) # 许文强 123456
return HttpResponse(f'提交成功 \n 返回数据:\nname:{name}\npwd:{pwd}')
return render(request,'ajax_json.html')
- 模板层 ajax_json.html 文件
// html 标签
<form action="" >
用户名:
<input type="text" class="form-control" id="a1">
密码:
<input type="password" class="form-control" id="a2">
<br>
<input type="button" class="btn btn-warning btn-block" value=" 上传信息 ">
</form>
// script
<script>
$('.btn').click(function () {var name = $('#a1').val()
var pwd = $('#a2').val()
var data = JSON.stringify({'name':name,'pwd':pwd}) // 将其转成 json 格式字符串
$.ajax({
url:'ajax_json',
method:'post',
contentType:'application/json', // 指定数据格式
data:data, // json 格式的数据, 需要与上面指定的一致
success:function (args) {alert(args)
}
})
})
</script>
2. 效果展示
九.django 自带的序列化组件(序列化器)
1. 组件介绍
- 导入组件
from django.core import serializers
- 组件使用 / 参数介绍
serializers.serialize('json', user_queryset)
# 第一个参数是指定需要序列化的类型
# 第二个参数是指定需要序列化的数据
# 返回的结果是一个列表套字典格式的序列化之后的数据
2. 代码示例
from django.core import serializers
def dj_json(request):
user_list = models.User.objects.all()
res = serializers.serialize("json",user_list)
return HttpResponse(res)
- 显示结果
从上面的结果我们可以发现 :
序列化器是将对象转成格式字符串, 但字段不能控制, 现阶段我们如果要做序列化, 最好使用 for 循环 + 列表套字典; 但这个组件在后面 drf 中会使用到
3. 使用 for 循环 + 列表套字典做序列化
def for_json(request):
user_list = models.User.objects.all()
l = []
for obj in user_list:
l.append({'id':obj.id,'name':obj.name,'pwd':obj.pwd})
return JsonResponse(l, safe=False)
- 显示结果
字段可控, 比较清晰
正文完