一.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":"xe8xaexb8xe6x96x87xe5xbcxba","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'提交成功
返回数据:
name:{name}
pwd:{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)
- 显示结果
字段可控, 比较清晰