AJAX
一.什么是Ajax
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互
Ajax是js中的技术,但原生的js操作Ajax比较复杂,我们这里为了提高效率,直接使用jQuery封装版本的Ajax
Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互
Ajax是js中的技术,但原生的js操作Ajax比较复杂,我们这里为了提高效率,直接使用jQuery封装版本的Ajax
二.优点
1.Ajax向服务器发送异步请求
2.Ajax请求无序刷新整个页面(局部刷新)
3.因为服务器响应内容不再是整个页面,而是页面的局部内容没所以Ajax性能高
'''局部刷新,异步请求'''
三.如何使用
/*基本参数:*/
1.url : 提交的地址
2.type : 提交的方式(默认GET)
3.data : 提交的数据
4.success : 回调函数(因为是异步提交,需要回调函数,取结果)
/*基本语法:*/ Ajax通常与事件绑定使用
$('#d1').click(function() {
$.ajax({
url:'/index/', // 提交的地址
type:'post', // 提交的方式
data:{'name':'xionger', 'password':'123'} // 提交的数据
success:function(data) {
alert(data) // data接收的就是异步提交返回的结果
}
})
})
求和实例:
<!--前端-->
<body>
<input type="text" id="id1"> + <input type="text" id="id2"> = <input type="text" id="id3">
<button id="b1">求和</button>
<script>
$('#b1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'id1':$('#id1').val(),'id2':$('#id2').val()},
success:function (data) {
// {alert(data)} data形参用来接收异步提交的结果
$('#id3').val(data) // 通过DOM操作,将结果渲染到第三个input框中
}
})
})
</script>
</body>
# 后端
def index(request):
if request.is_ajax(): # 判断是否是Ajax
if request.method == 'POST': # POST 方式请求的数据都在POST中
id1 = request.POST.get('id1')
id2 = request.POST.get('id2')
# 数据传输过来d都是字符串,强转整型
id1 = int(id1)
id2 = int(id2)
res = id1 + id2
# 将结果返回到前端
return HttpResponse(res)
return render(request, 'index.html')
contentType
一.前后端传输数据编码格式
1.urlencoded # form表单与Ajax默认的数据编码格式
2.formdata # form表单
3. json # Ajax
ps: Ajax传输文件建议使用内置对象: new Formdata()
'''注意:前后端传输数据的时候,一定要保证数据格式和你的编码格式是一致的'''
1.urlencoded
1.数据格式: name=xionger&password=123
2.Django后端针对urlencoded编码格式的数据会自动解析并放到 request.POST 中.
3.form表单与Ajax默认的数据编码格式
2.formdata
1.form表单传输文件的编码格式
2.Django后端针对form表单指定formdata格式传输文件就会自动解析并将文件放到request.FILES中
3.使用:<form action="" method="post" enctype="multipart/form-data">
3.json
1.Ajax发送json格式数据
2.Django后端针对json格式的数据,并不会自动解析放到request.POST或者request.FILES里面,
它并不会解析json格式数据,而是将它原封不动的放在request.body中
3.使用:data:JSOM.stringify({'name':'xionger', 'password':123})
ps:JSOM.stringify() 类似 json.dumps()
前后端传输数据的编码方式
1.urlencoded >>> name=jason&pwd=123&hobby=read
2.formdata >>> 传文件也支持传普通键值(name=jason&pwd=123&hobby=read)
3.application/json >>> json格式数据(form表单是无法发送json格式数据的)
form,ajax默认的是urlencoded
django后端针对不同的编码格式是如何处理的?
只要是符合urlencoded编码格式 都会被后端自动获取并解析放到request.POST中
如果是符合formdata那么文件会自动被解析放到request.FILES中
如果是json格式 后端默认不解析 以二进制的形式就放在request.body你可以自己手动处理即可
contentType总结
二.Ajax发送json格式与文件实例
1.发送json格式数据
<!--前端-->
<body>
<input type="text" id="name" > <input type="text" id="pwd" >
<button id="b1">登录</button>
<script>
$('#b1').click(function () {
$.ajax({
url:'',
type:'post',
data:JSON.stringify({'id1':$('#name').val(),'id2':$('#pwd').val()}),
contentType:'application/json', // 告诉后端传世的数据时json格式
success:function (data) {
{alert(data)} // data形参用来接收异步提交的结果
$('#id3').val(data) // 通过DOM操作,将结果渲染到第三个input框中
}
})
})
</script>
</body>
# 后端
import json
def login(request):
if request.is_ajax(): # 判断是否是Ajax
if request.method == 'POST':
json_bytes = request.body # 前端json格式传输的数据都在request.body中
# 在request.body中,json格式的数据没有任何处理,是二进制形式,需要后端反序列化
print(json.loads(json_bytes)) # {'id1': 'xionger', 'id2': '123'}
name = json.loads(json_bytes).get('name')
password = json.loads(json_bytes).get('pwd')
print(name) # xionger
print(password) # 123
# 将结果返回到前端
return HttpResponse('OK')
return render(request, 'ajax_json.html')
发送文件
# 如何获取文件标签所存储的文件对象? 固定语法:
1.先用jQery查找到存储文件的input标签
2.将jQuery对象转成原生js对象
3.利用原生js对象的方法 $('input')[0].files[0]获取到标签内部存储的文件对象
4.一定要指定两个参数都为false
# ajax发送文件需要指定两个额外的参数
1.processData:false, # 告诉前端不要处理数据
2.contentType:false, # 不适用任何编码 因为formdata对象自身自带编码django后端也能够识别formdata对象
1.利用内置对象FormData
既可以传文件也可以传普通的键值对
2.获取input标签存储的文件对象
先用jQuery找到该input标签,然后转成原生的js对象
然后固定语法.files[0]
$('input')[0].files[0]
3.发送ajax请求
有两个关键性的参数需要你指定
processData:false
contentType:false
django后端就会普通的键值解析到request.POST中文件解析到request.FILES
注意
<body>
<script>
$('#b1').on('click',function () {
// ajax传输文件 建议使用内置对象formdata
var formData = new FormData(); // 既可以传普通的键值对 也可以传文件
// 添加普通键值
formData.append('username','jason');
formData.append('password','123');
// 传文件
// 如何获取文件标签所存储的文件对象? 固定语法
// 1.先用jQery查找到存储文件的input标签
// 2.将jQuery对象转成原生js对象
// 3.利用原生js对象的方法 .files[0]获取到标签内部存储的文件对象
// 4.一定要指定两个参数都为false
formData.append('my_file',$('#d1')[0].files[0]);
$.ajax({
url:'', // 控制发送给谁 不写就是朝当前地址提交
type:'post', // 发送方式是post请求
data:formData, // 发送的数据
// ajax发送文件需要指定两个额外的参数
processData:false, // 告诉前端不要处理数据
contentType:false, // 不适用任何编码 因为formdata对象自身自带编码 django后端也能够识别formdata对象
success:function (data) { // data形参用来接收异步提交的结果
{alert(data)}
$('#i3').val(data)
}
})
})
</script>
</body>
实例-前端代码
Ajax删除按钮实例
利用ajax删除实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'dist/sweetalert.min.js' %}"></script>
<style>
div.sweet-alert h2{
padding-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h2 class="text-center">数据展示</h2>
<table class="table-striped table table-hover table-bordered">
<thead>
<tr>
<th>序号</th>
<th>主键</th>
<th>用户名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user in user_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ user.pk }}</td>
<td>{{ user.username }}</td>
<td>{{ user.age }}</td>
<td>{{ user.get_gender_display }}</td>
<td>
<button class="btn btn-primary btn-sm">编辑</button>
<button class="btn btn-danger btn-sm del" user_id="{{ user.pk }}">删除</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script>
$('.del').click(function () {
// 获取当前标签对象
var $btnEle = $(this);
swal({
title: "你确定要删吗?",
text: "你要是删了,你就准备跑路吧!",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "是的,老子就要删!",
cancelButtonText: "算了,算了!",
closeOnConfirm: false,
showLoaderOnConfirm: true
},
function(){
// 朝后端发送ajax请求
$.ajax({
url:'',
type:'post',
data:{'delete_id':$btnEle.attr('user_id')},
success:function (data) { // 后端发字典过来 前端不需要你手动转 会自动帮你转换成js自定义对象
if (data.code == 100){
{#window.location.href = ''; // 不写就是跳到当前页面#}
// 通过DOM操作 实时改变页面
// 将被点击的删除按钮所在的那一行直接从DOM树中删掉
$btnEle.parent().parent().remove();
swal("删掉了!", "赶紧回去收拾行李吧,准备跑路!", "success");
}else{
swal('发生了未知的错误','估计是有bug了','info')
}
}
});
});
})
</script>
</body>
</html>
html.py
class User(models.Model):
username = models.CharField(max_length=32)
age = models.CharField(max_length=32)
choices = (
(1,'男'),(2,'女'),(3,'其他')
)
gender = models.IntegerField(choices=choices)
"""
1 存choice里面罗列的数字与中文对应关系
print(user_obj.get_gender_display())
只要是choices字段 在获取数字对应的注释 固定语法
get_choices字段名_display()
2 存没有罗列迟来的数字
不会报错 还是展示数字
"""
models.py
from app01 import models
from django.http import JsonResponse
def userlist(request):
if request.is_ajax():
"""
一般情况下 针对ajax请求 后端通常都是返回一个字典
"""
back_dic = {'code':100, 'msg':''} # code用于前端校验是否删除成功
# 拿到指定删除对象的id
delete_id = request.POST.get('delete_id')
models.User.objects.filter(pk=delete_id).delete()
# 给前端ajax返回一个消息字典
back_dic['msg'] = '删除成功'
return JsonResponse(back_dic)
user_list = models.User.objects.all()
return render(request, 'userlist.html',locals())
views.py
分页器
<!--前端-->
{% for book in page_queryset %}
<p>{{ book.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
# 后端
book_list = models.Book.objects.all()
current_page = request.GET.get("page",1)
all_count = book_list.count()
page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10,pager_count=5)
page_queryset = book_list[page_obj.start:page_obj.end]
分页器模板代码
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
utils文件中mypage.py
from app01.utils.mypage import Pagination
def book(request):
book_list = models.Book.objects.all()
current_page = request.GET.get("page",1)
all_count = book_list.count()
page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
page_queryset = book_list[page_obj.start:page_obj.end]
return render(request,'booklist.html',locals())
views.py
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book in page_queryset %}
<p>{{ book.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
</div>
</div>
</div>
</body>
前端
补充
Django 序列化组件
什么时候用
后端想直接将实例化出来的数据对象直接发送给客户端,那么这个时候,就可以用Django给我们提供的序列化方式
# 后端:
def ser(request):
#拿到用户表里面的所有的用户对象
user_list=models.User.objects.all()
#导入内置序列化模块
from django.core import serializers
#调用该模块下的方法,第一个参数是你想以什么样的方式序列化你的数据
ret=serializers.serialize('json',user_list)
return render(request,'index.html',locals())
# 前端得到:
[{"model": "app01.user","pk": 1,"fields":
{"username": "jason","age": 18,"gender": 1}
}......]
bulk_create 批量插入数据(高效)
l = []
for i in range(10000):
l.append(models.Book2(name='第%s本书'%i))
models.Book2.objects.bulk_create(l) # 批量插入数据
choices字段参数
为什么用
1.对于类型性别,假否,婚否的字段,有固定字段数据的字段可以用choices参数
2.节省空间,因为存的是数字
对于类型性别,假否,婚否的字段,有固定字段数据的字段可以用choices参数
2.节省空间,因为存的是数字
如何使用
# models.py文件中:
class User(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
choices = (
(1,'男'),(2,'女'),(3,'其他')
)
gender = models.IntegerField(choices=choices) # 指定choices参数
"""
1 存choice里面罗列的数字与中文对应关系
print(user_obj.get_gender_display())
只要是choices字段 在获取数字对应的注释 固定语法
get_字段名_display()
2 存没有罗列出来的数字
不会报错 还是展示数字
"""
# views.py文件中
def userlist(request):
user_obj = models.User.objects.filter(pk=1).first()
gender = user_obj.get_gender_display() # 得到对应的性别注释,如'男'