10-7,Django_Learn之Ajax
Posted 吴平凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10-7,Django_Learn之Ajax相关的知识,希望对你有一定的参考价值。
7 Ajax
7.1 Ajax简介
异步提交,局部刷新
其最大优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
例子:GitHub注册,动态获取用户名实时跟后端确认并实时展示的前端(局部刷新)
向后端发送请求的方式:
GET请求
GET请求
GET/POST请求
GET/POST请求
只学习jQuery封装之后的版本(不学原生,复杂且一般不用),所以使用ajax时需要确保导入了jquery。ps:并不只有jQuery能实现ajax,其他的框架也可以,换汤不换药。
def ab_ajax(request):
if request.method == 'POST':
# print(request.POST) # <QueryDict: {'username': ['Jack'], 'password': ['123']}>
# <QueryDict: {'i1': ['111'], 'i2': ['222']}>
i1 = request.POST.get('i1')
i2 = request.POST.get('i2')
# # # 先转型再加
i3 = int(i1) + int(i2)
# print(i3)
# d = {'code':100,'msg':i3}
# d = {'code':100,'msg':666}
return HttpResponse(i3)
# return HttpResponse(d)
# return HttpResponse(json.dumps(d))
# return JsonResponse(d)
return render(request, 'ab_ajax.html')
<input type="text" id="d1"> +
<input type="text" id="d2"> =
<input type="text" id="d3">
<br/>
<br/>
<p>
<button id="btn">点我</button>
</p>
<script>
// 先给按钮绑定一个点击事件
$('#btn').click(function () {
//朝后端发送ajax请求
$.ajax({
//1,指定朝哪个后端发送ajax请求
url: '',// 不写就是向当前地址提交
//2,请求方式
type: 'post',//不指定默认是get请求
//3,数据
{#data:{'username':'Jack','age':23},#}
data: {'i1': $('#d1').val(), 'i2': $('#d2').val()},
//4,回调函数(异步回调机制):当后端返回结果时自动触发 args接收返回的结果
{#dataType:true, //会自动反序列化#}
success: function (args) {
{#alert(args) // 通过DOM操作动态渲染到第三个input里面#}
$('#d3').val(args)
{#console.log(typeof args)#}
}
})
})
</script>
此时运行之后有
"""
后端如果是用HttpResponse返回的数据,回调函数不会自动反序列化
如果后端用的是JsonResponse返回的数据,回调函数会自动反序列化
就是想用HttpResponse方法:
1,在前端利用JSON.parse()
2,在ajax里配置一个参数
"""
7.2 前后端传输数据的编码格式(contentType)(了解)
主要post请求数据的编码格式
可以向后端发送post请求的方式
前后端传输数据的三种格式
def index(request):
if request.method == "POST":
print(request.POST)
print(request.FILES)
return render(request, 'index.html')
<form action="" method="post" enctype="multipart/form-data">
{#<form action="" method="post">#}
<p>username:<input type="text" name="username" class="form-control"></p>
<p>password:<input type="text" name="password" class="form-control"></p>
<p>file:<input type="file" name="file"></p>
<input type="submit" class="btn btn-success">
<input type="button" class="btn btn-danger" value="按钮" id="d1">
</form>
7.2.1 研究form表单
7.2.2 研究ajax
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'Jack','age':23},
success:function (args) {
}
})
})
</script>
7.3 ajax发送json格式数据
前后端传输数据是一定要确保编码格式跟数据真正的格式是一致的
request对象方法补充
views.py
import json
def ab_json(request):
if request.is_ajax():
# print(request.is_ajax()) # True
# print(request.POST) # <QueryDict: {}>
# print(request.FILES) # <MultiValueDict: {}>
# print(request.body) # b'{"username":"Jack","age":23}'
# 针对json格式数据需要手动处理
json_bytes = request.body
# json_str = json_bytes.decode('utf-8')
# json_dict = json.loads(json_str)
# print(json_dict,type(json_dict)) # {'username': 'Jack', 'age': 23} <class 'dict'>
# json.loads()括号内若传入了一个二进制格式的数据则内部会自动解码在反序列化
json_dict = json.loads(json_bytes)
print(json_dict, type(json_dict)) # {'username': 'Jack', 'age': 23} <class 'dict'>
return render(request, 'ab_json.html')
ab_json.html
<button class="btn btn-danger" id="d1">点我</button>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
{#data:{'username':'Jack','age':23},//此格式会报错#}
data:JSON.stringify({'username':'Jack','age':23}),//转成json格式
contentType:'application/json',//指定编码格式
success:function () {
}
})
})
</script>
点击之后有
ajax发送json数据需要注意
7.4 ajax发送文件
views.py
def ab_file(request):
if request.is_ajax():
if request.method == "POST":
print(request.POST)
print(request.FILES)
return render(request, 'ab_file.html')
ab_file.html
<p>username:<input type="text" id="d1"></p>
<p>password:<input type="text" id="d2"></p>
<p><input type="file" id="d3"></p>
<button class="btn btn-info" id="d4">点我</button>
<script>
//向后端发送普通键值对和文件数据
$('#d4').on('click', function () {
// 1 需要先利用FormData内置对象
let formDataObj = new FormData();
// 2 添加普通键值对
formDataObj.append('username', $('#d1').val())
formDataObj.append('password', $('#d2').val())
// 3 添加文件对象
formDataObj.append('myfile', $('#d3')[0].files[0])
// 4 将对象基于ajax发送给后端
$.ajax({
url: '',
type: 'post',
data: formDataObj,// 直接将对象放在data后面即可
// ajax 发送文件必须指定的两个参数
contentType: false,// 不需要使用任何编码,django后端可以自动识别formData对象
processData: false,// 告诉浏览器不要对数据做任何处理
sucess: function (args) {
}
})
})
</script>
运行点击之后
总结:
7.5 django自带的序列化组件(drf铺垫)
views.py
import json
from django.core import serializers
def ab_ser(request):
user_queryset = models.User.objects.all()
# return render(request,'ab_ser.html',locals())
# [{},{},{},...]
# user_list = []
# for user_obj in user_queryset:
# tmp = {
# 'pk': user_obj.pk,
# 'name': user_obj.name,
# 'age': user_obj.age,
# 'gender': user_obj.get_gender_display()
# }
# user_list.append(tmp)
# return JsonResponse(user_list, safe=False)
'''
[{
"pk": 1,
"name": "Jack",
"age": 20,
"gender": "male"
},
{
"pk": 2,
"name": "Amy",
"age": 15,
"gender": "female"
},
{
"pk": 3,
"name": "Bob",
"age": 30,
"gender": "male"
},
{
"pk": 4,
"name": "Sum",
"age": 40,
"gender": "male"
}
]
前后端分离的
作为后端只需要写代码将数据处理好能够序列化返回给前端即可
再写一个接口文档,告诉前端每个字段代表的意思即可
'''
# 序列化
res = serializers.serialize('json', user_queryset)
"""会自动将数据变成json格式的字符串,且内部非常全面"""
return HttpResponse(res)
"""
[{
"model": "app01.user",
"pk": 1,
"fields": {
"name": "Jack",
"age": 20,
"gender": 1
}
}, {
"model": "app01.user",
"pk": 2,
"fields": {
"name": "Amy",
"age": 15,
"gender": 2
}
}, {
"model": "app01.user",
"pk": 3,
"fields": {
"name": "Bob",
"age": 30,
"gender": 1
}
}, {
"model": "app01.user",
"pk": 4,
"fields": {
"name": "Sum",
"age": 40,
"gender": 1
}
}]
写接口就是利用序列化组件渲染数据然后写一个接口文档,该交代交代一下
"""
ab_ser.html
{% for user_obj in user_queryset %}
<p>{{ user_obj }}</p>
{% endfor %}
7.6 ajax结合sweetalert
要学会如何拷贝
学会基于别人的基础之上做修改
研究各个参数表示的意思,然后照葫芦画瓢
后端:
import time
def user_list(request):
user_queryset = models.User.objects.all()
return render(request, 'user_list.html', locals())
def delete_user(request):
"""
前后端在用ajax进行交互的时候,后端通常给ajax的回调函数返回一个字典格式的数据
"""
if request.is_ajax():
if request.method == "POST":
back_dic = {'code': 1000, 'msg': ''}
time.sleep(3) # 模拟操作数据的延迟
delete_id = request.POST.get('delete_id')
models.User.objects.filter(pk=delete_id).delete()
# 需要告诉前端操作的结果
back_dic['msg'] = '数据已经删了,你赶紧跑路吧'
return JsonResponse(back_dic)
前端:
<div class="container-fluid">
<h1 class="text-center">用户展示</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>ID</th>
<th>name</th>
<th>age</th>
<th>gender</th>
<th>actions</th>
</tr>
</thead>
{% for user_obj in user_queryset %}
<tbody>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ user_obj.name }}</td>
<td>{{ user_obj.age }}</td>
<td>{{ user_obj.get_gender_display }}</td>
<td>
<button class="btn btn-warning btn-xs">编辑</button>
<button class="btn btn-danger btn-xs del" delete_id="{{ user_obj.pk }}">删除</button>
<!--因为其在循环中,所以不能直接加id,需要添加class-->
</td>
</tr>
</tbody>
{% endfor %}
</table>
</div>
</div>
</div>
<script>
$('.del').on('click', function () {
//先将当前标签对象存储起来
let currentBtn = $(this);
// alert(123)
// alert($(this).attr('delete_id'))
// 二次确认弹框
swal({
title: "确定删除吗?",
text: "你可要考虑清楚了,可能需要拎包跑路额",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "是的,老子就要删",
cancelButtonText: "算了,算了!",
closeOnConfirm: false,
closeOnCancel: false,
// showLoaderOnConfirm: true
},
function (isConfirm) {
if (isConfirm) {
// 向后端发送ajax请求删除数据后 再弹框
$.ajax({
// url:'/delete/user/'+currentBtn.attr('delete_id'),//1 传递主键值方式1
url: '/delete/user/', // 2 放在请求体里
type: 'post',
data: {'delete_id': currentBtn.attr('delete_id')},
success: function (args) { // args = {'code':'','msg':''}
// 判断响应状态码,然后做不同处理
if (args.code === 1000) {
swal('删了', args.msg, 'sucess')
// 1 lowb版本 直接刷新当前页面
// window.location.reload()
// 2 利用DOM操作动态刷新
currentBtn.parent().parent().remove()
} else {
swal('完了', '出现了未知的错误', 'info')
}
}
})
swal("删除!", "赶紧跑路吧。",
"success");
} else {
swal("怂逼", "不要说我认识你",
"error");
}
});
})
</script>
7.7 批量插入
普通版(耗时较长)
views.py
def ab_pl(request):
# 先给book插入300条数据
for i in range(300):
models.Book.objects.create(title="第%s本书"%i)
# 再讲所有的数据查询并展示到页面
book_queryset = models.Book.objects.all()
return render(request,'ab_pl.html',locals())#耗时较长
ab_pl.html
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
有批量插入版(bulk_create)
# 批量插入
book_list = []
for i in range(300):
book_obj = models.Book(title="第%s本书"%i)
book_list.append(book_obj)
models.Book.objects.bulk_create(book_list)
book_queryset = models.Book.objects.all()
"""
当批量插入数据时,使用orm提供的bulk_create能够大大减少操作时间
"""
速度提升明显。
7.8 分页器
注:制作页码时一般都是奇数个,符合国人对对称美的标准
分页器推导
# 分页
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
#终止位置
current_page * per_page_num =
book_queryset = models.Book.objects.all()[start_page:end_page]
return render(request,'ab_fenye.html',locals())
运行,取bootstrap中的分页代码粘贴到html文件中,在浏览器输入相关网址可以得到
在程序中再添加
all_count = book_list.count()
page_count, more = divmod(all_count, per_page_num)
if more:
page_count += 1
page_html = ''
for i in range(1,page_count+1):
page_html += '<li><a href="?page=%s">%s</a></li>' % (i, i)
book_queryset = book_list[start_page:end_page]
return render(request, 'ab_pl.html', locals())
html文件代码改为
{% for foo in book_queryset %}
<p>{{ foo.title }}</p>
{% endfor %}
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{{ page_html|safe }}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
则有
再对函数进行调整
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)
则可以得到
7.9 自定义分页器的拷贝及使用
当需要使用到非django内置的第三方功能或者组件代码时,一般会创建一个名为utils的文件夹,在该文件夹内对模块进行功能性划分
后期封装代码时,不再局限于函数,而是尽量使用面向对象封装
后端:
from utils.mypage import Pagination
def ab_pl(request):
book_queryset = models.Book.objects.all()
current_page = request.GET.get('page', 1)
all_count = book_queryset.count()
# 1 传值生成对象
page_obj = Pagination(current_page=current_page, all_count=all_count)
# 2 直接对总数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
# 3 将page_queryset传递到页面,替换之前的book_queryset
return render(request, 'ab_pl.html', locals())
前端
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
<nav aria-label="Page navigation">
</nav>
{% endfor %}
{#利用自定义分页器直接显示分页器样式#}
{{ page_obj.page_html|safe }}
运行有
以上是关于10-7,Django_Learn之Ajax的主要内容,如果未能解决你的问题,请参考以下文章
Json与Ajax交互报错解决No converter found for return value of type: class com.github.pagehelper.PageInfo(代码片
Json与Ajax交互报错解决No converter found for return value of type: class com.github.pagehelper.PageInfo(代码片