AJax
目录
Ajax简介
- AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
- AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
Ajax特点
- 异步提交,客户端发出一个请求之后,无需等待服务器相应结束就可以发送第二个请求。
- 局部刷新
- 具体案例请看github的注册页面,动态获取用户名实时跟后端确认并展示到前端(局部刷新)
Ajax初识 --- 小案例
页面输入两个整数,通过AJAX传输到后端计算出结果并返回。
页面上有三个input框
在前两个框中输入数字 点击按钮 朝后端发送ajax请求
后端计算出结果 再返回给前端动态展示的到第三个input框中
(整个过程页面不准有刷新,也不能在前端计算)
$('#btn').click(function () {
// 朝后端发送ajax请求
$.ajax({
// 1.指定朝哪个后端发送ajax请求
url:'', // 不写就是朝当前地址提交
// 2.请求方式
type:'post', // 不指定默认就是get 都是小写
// 3.数据
{#data:{'username':'jason','password':123},#}
data:{'i1':$('#d1').val(),'i2':$('#d2').val()},
// 4.回调函数:当后端给你返回结果的时候会自动触发 args接受后端的返回结果
success:function (args) {
{#alert(args) // 通过DOM操作动态渲染到第三个input里面#}
{#$('#d3').val(args)#}
console.log(typeof args)
}
})
})
针对后端如果是用HttpResponse返回的数据 回调函数不会自动帮你反序列化
如果后端直接用的是JsonResponse返回的数据 回调函数会自动帮你反序列化
前后端传输数据的编码格式(contentType)
前后端传输数据的编码格式
- urlencoded
- formdata
- json
get请求(了解即可)
get请求数据就是直接放在url?的后面
url?username=xxx&pwd=111
post请求(重点)
可以朝后端发送post请求的方式有两种:form表单 和 ajax请求
form表单默认的数据编码格式
默认的数据编码格式是urlencoded
数据格式:username=tank&password=456
结论:
- django后端针对符合urlencoded编码格式的前端数据(类似于username=tank&password=456)都会自动解析封装到request.POST中
- 如果编码格式formdata,针对普通的键值对还是解析到request.POST中,而将文件解析到request.FILES中
- form表单无法发送json格式的数据
ajax请求默认的数据编码格式
默认的数据编码格式是urlencoded
数据格式:username=tank&password=456
- django后端针对符合urlencoded编码格式的前端数据(类似于username=tank&password=456)都会自动解析封装到request.POST中
- 如果编码格式formdata,针对普通的键值对还是解析到request.POST中,而将文件解析到request.FILES中
- ajax请求可以发送json格式的数据
ajax发送json格式的数据
前后端传输数据的时候一定要确保编码格式和数据真正的格式是一致的
<body>
<button class="btn btn-danger" id="d1"></button>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
{#因为指定了编码格式所以这里要将自定义对象进行序列化#}
data:JSON.stringify({'name':'tank'}),
{#指定编码格式,默认是urlencoded,编码格式指定完成后一定要确保发送给后端的数据格式与指定的编码格式是一致的#}
contentType:'application/json',
success:function () {
}
})
})
</script>
</body>
import json
def ab_json(request):
# Django后端针对前段发送过来的json格式的数据不会做任何的处理,前端发送的json格式的数据在request.body中(一定不会在request.POST中,因为数据格式不是urlencoded),Django后端需要手动处理json格式的数据,进行反序列化
if request.is_ajax():
json_obj = request.body
print(json_obj) # b'{"name":"tank"}'
# 因为前后端交互是通过二进制的数据,因此通过request.body得到的json格式的数据是二进制的格式,需要解码,然后进行反序列化
json_str = json_bytes.decode('utf-8')
json_dict = json.loads(json_str)
# json.loads括号内如果传入了一个二进制格式的数据其实内部自动解码再反序列化
json_dict = json.loads(json_bytes)
return render(request,'ab.html')
- 总结
ajax发送json格式数据需要注意点
1.contentType参数指定成:application/json
2.数据是真正的json格式数据
3.django后端不会帮你处理json格式数据需要你自己去request.body获取并处理
ajax发送文件
<body>
username <input type="text" id="d1">
password <input type="text" id="d2">
file <input type="file" id="d3">
<button class="btn btn-danger" id="d4">点我</button>
<script>
$('.btn').on('click',function () {
{#1 首先需要利用FormData内置对象#}
let $formDataObj = new FormData();
{#添加普通的键值对,这里的键就类似与form表单中需要指定的name属性#}
$formDataObj.append('username',$('#d1').val());
$formDataObj.append('password',$('#d2').val());
{#添加文件对象,$('#d3')[0]jQuery对象转为js对象,在获取到文件对象#}
$formDataObj.append('myfile',$('#d3')[0].files[0]);
$.ajax({
url:'',
type:'post',
{#直接将对象放在data后面即可#}
data:$formDataObj,
{# ajax发送文件必须指定两个参数 #}
contentType:false, {# 不需要使用任何编码,Django后端能够自动识别formdata对象 #}
processData: false,{# 告诉浏览器不要对formdata对象中的数据进行任何处理 #}
success:function () {
}
})
})
</script>
</body>
def files(request):
if request.is_ajax():
if request.method == 'POST':
print(request.POST)
print(request.FILES)
return render(request,'file.html')
- 总结
1.ajax发送文件需要利用内置对象FormData
2.可以添加普通的键值对
3.可以添加文件对象
4.添加文件对象时,需要指定两个参数:
contentType:false
processData:false
5.django后端能够直接识别到formdata对象并且能够将内部的普通键值自动解析并封装到request.POST中 文件数据自动解析并封装到request.FILES中
Django自带的序列化组件
- 需求
在前端获取到后端用户表中的所有数据,并且是列表套字段
- 自己写代码实现
import json
from django.http import JsonResponse
from django.core import serializers
def ab_ser(request):
user_queryset = models.User.objects.all()
# [{},{},{},{},{}]
# user_list = []
# for user_obj in user_queryset:
# tmp = {
# 'pk':user_obj.pk,
# 'username':user_obj.username,
# 'age':user_obj.age,
# 'gender':user_obj.get_gender_display()
# }
# user_list.append(tmp)
# return JsonResponse(user_list,safe=False)
# return render(request,'ab_ser.html',locals())
// 前端接收到的数据格式
[
{"pk": 1, "username": "jason", "age": 25, "gender": "male"},
{"pk": 2, "username": "egon", "age": 31, "gender": "female"},
{"pk": 3, "username": "kevin", "age": 32, "gender": "others"},
{"pk": 4, "username": "tank", "age": 40, "gender": 4}
- django自带序列化模块
res = serializers.serialize('json',user_queryset)
"""会自动帮你将数据变成json格式的字符串 并且内部非常的全面"""
return HttpResponse(res)
// 前端接收到的数据格式
[
{ "model": "app01.user",
"pk": 1,
"fields": {"username": "jason", "age": 25, "gender": 1}},
{ "model": "app01.user",
"pk": 2,
"fields": {"username": "egon", "age": 31, "gender": 2}},
{ "model": "app01.user",
"pk": 3,
"fields": {"username": "kevin", "age": 32, "gender": 3}},
{ "model": "app01.user",
"pk": 4,
"fields": {"username": "tank", "age": 40, "gender": 4}}
]
- 补充知识
前后端分离的项目,后端只需要写代码将数据处理好,能够序列化返回给前端即可
最后写一个稳当借口,告诉前端每个字段代表的意思即可
ajax结合sweetalert
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>author</th>
<th>
action
</th>
</tr>
</thead>
<tbody>
{% for book_obj in all_book_obj %}
<tr>
<td>{{ book_obj.id }}</td>
<td>{{ book_obj.name }}</td>
<td>{{book_obj.author}}</td>
<td>
<button class="btn btn-xs btn-danger del" delete_id="{{ book_obj.pk }}">删除</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script>
$('.del').on('click',(function () {
{#// 现将当前标签存储起来#}
let currentBtn = $(this);
swal({
title: "确定要删除?",
text: "要考虑清楚呀",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "没错,忍够了!",
cancelButtonText: "要不还是再忍忍!",
closeOnConfirm: false,
closeOnCancel: false,
showLoaderOnConfirm: true
},
function(isConfirm) {
if (isConfirm) {
{# 向后端发送ajax请求删除数据之后,在弹出下面的提示框 #}
$.ajax({
url:'',
type:'post',
data:{'del_id':currentBtn.attr('delete_id')},
success:function (args) {
if (args.code === 1000) {
swal("删除了!", args.msg, "success");
currentBtn.parent().parent().remove()
}
else
{swal('完蛋了!','出现了未知的错误','info')
}
}
});
} else {
swal("还是不敢删", "默默回去干活吧", "error");
}
});
}))
</script>
</body>
- 总结
自己要学会如何拷贝
学会基于别人的基础之上做修改
研究各个参数表示的意思 然后找葫芦画瓢
向数据库中批量插入数据
def ab_pl(request):
# 先给Book插入一万条数据
# for i in range(10000):
# models.Book.objects.create(title='第%s本书'%i)
# # 再将所有的数据查询并展示到前端页面
book_queryset = models.Book.objects.all()
# 批量插入
# book_list = []
# for i in range(100000):
# book_obj = models.Book(title='第%s本书'%i)
# book_list.append(book_obj)
# models.Book.objects.bulk_create(book_list)
"""
当你想要批量插入数据的时候 使用orm给你提供的bulk_create能够大大的减少操作时间
:param request:
:return:
"""
return render(request,'ab_pl.html',locals())
分页器内部原理
"""
总数据100 每页展示10 需要10
总数据101 每页展示10 需要11
总数据99 每页展示10 需要10
如何通过代码动态的计算出到底需要多少页?
在制作页码个数的时候 一般情况下都是奇数个 符合中国人对称美的标准
"""
# 分页
book_list = models.Book.objects.all()
# 想访问哪一页
current_page = request.GET.get('page',1) # 如果获取不到当前页码 就展示第一页
# 数据类型转换
try:
current_page = int(current_page)
except Exception:
current_page = 1
# 每页展示多少条
per_page_num = 10
# 起始位置
start_page = (current_page - 1) * per_page_num
# 终止位置
end_page = current_page * per_page_num
# 计算出到底需要多少页
all_count = book_list.count()
page_count, more = divmod(all_count, per_page_num)
if more:
page_count += 1
page_html = ''
xxx = current_page
if current_page < 6:
current_page = 6
for i in range(current_page-5,current_page+6):
if xxx == i:
page_html += '<li class="active"><a href="?page=%s">%s</a></li>'%(i,i)
else:
page_html += '<li><a href="?page=%s">%s</a></li>'%(i,i)
book_queryset = book_list[start_page:end_page]
"""
django中有自带的分页器模块 但是书写起来很麻烦并且功能太简单
所以我们自己想法和设法的写自定义分页器
上述推导代码你无需掌握 只需要知道内部逻辑即可
我们基于上述的思路 已经封装好了我们自己的自定义分页器
之后需要使用直接拷贝即可
"""