八:传输数据编码,orm
目录
前后传递数据的编码格式(contentType)
# 朝后端发送post请求的两种方式
(1)通过form表单的方式
(2)通过ajax请求
- 通过form表单的方式
form表单的默认编码格式是urlencoded
数据的默认格式是:username=wangpeng&password=123&file=blog_head.jpg
django后端针对符合urlencoded编码格式的数据都会自动帮你解析并封装到request.POST
里面
<QueryDict: {'csrfmiddlewaretoken': ['w72XW1HNfvY4horzz4cZNrOviFYEM9CLG4Qh5cx7jbSS1N1U2Z6p2vhMDJX4F1Nv'], 'username': ['wangpeng'], 'password': ['123'], 'file': ['blog_head.jpg']}>
但是,如果你把表单的编码格式变为form-data
,那么针对普通的键值对还是解析分装到request.POST
,将文件解析封装到request.FILEs
中
QueryDict: {'csrfmiddlewaretoken': ['acjQZkQWUJyHBvdCjDI7GsmAfAGb2Kurk97a8vGgYpsvlUNXMyCxVwPRAEFBVCFb'], 'username': ['wangpeng'], 'password': ['123']}>
<MultiValueDict: {'file': [<InMemoryUploadedFile: blog_head.jpg (image/jpeg)>]}>
- 通过ajax的请求方式
ajax请求的默认编码格式也是urlencoded
数据的默认格式:username=jason&password=dbj123
<QueryDict: {'username': ['jason'], 'password': ['dbj123'], 'csrfmiddlewaretoken': ['Bt9MXqTPuqySdrXMIu9oFD546K8sLgfuLqX66BJ9y6sGXQx7bp3OUHylrO7SE8qe']}>
<MultiValueDict: {}>
重点:django后端针对编码格式为urlencoded的数据,会自动帮你解析并分装到request.POST中。
ajax发送json格式的数据
"""
前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的
"""
django后端针对json格式的数据不会做任何处理
def index(request):
if request.is_ajax():
json_bytes = request.body
json_str = json_bytes.decode('utf-8')
data_dic = json.loads(json_str)
print(data_dic,type(data_dic))
return render(request, 'index.html')
index.html
<script>
let $btnEle = $('#d1');
$btnEle.on('click', function () {
$.ajax({
url: '',//方式同表单的action,不写朝当前页面提交
type: 'post',//提交方式,不写默认为get
data: JSON.stringify({
"username": "jason",
"password": "dbj123",
}),
contentType:'application/json', // 指定编码格式
success: function (args) {//异步回调函数
},
})
})
</script>
此外,son.loads括号内如果传入了一个二进制格式的数据那么内部自动解码再反序列化
json_dict = json.loads(json_bytes)
ajax发送json格式数据需要注意点
1.contentType参数指定成:application/json
2.数据是真正的json格式数据
3.django后端不会帮你处理json格式数据需要你自己去request.body获取并处理
ajax发送文件数据
"""
ajax发送文件需要借助于js内置对象FormData
"""
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h3 class="text-center">注册页面
<span class="glyphicon glyphicon-user" style="color: blue"></span>
</h3><br>
<table class="table table-hover table-bordered table-striped">
<tbody>
<tr>
<td class="text-center">UserName</td>
<td>
<input type="text" id="d1" name="username" class="form-control" placeholder="UserName~">
</td>
</tr>
<tr>
<td class="text-center">Password</td>
<td>
<input type="password" id="d2" name="password" class="form-control" placeholder="Password~">
</td>
</tr>
<tr>
<td class="text-center">Image</td>
<td>
<input type="file" id="d3" name="image" class="form-control">
</td>
</tr>
</tbody>
</table>
<div class="text-center">
<button type="submit" id="d4" class="btn btn-success btn-sm">提 交</button>
</div>
</div>
</div>
</div>
<script>
$btnEle = $('#d4');
$btnEle.on('click', function () {
// 1 需要先利用FormData内置对象
let formDataObj = new FormData();
// 2 添加普通的键值对
formDataObj.append('username', $('#d1').val());
formDataObj.append('password', $('#d2').val());
// 3 添加文件对象
formDataObj.append('image', $('#d3')[0].files[0]);
// 4 将对象基于ajax发送给后端
$.ajax({
url: '',
type: 'post',
data: formDataObj,// 直接将对象放在data后面即可
// ajax发送文件必须要指定的两个参数
contentType: false, // 不需使用任何编码 django后端能够自动识别formdata对象
processData: false, // 告诉你的浏览器不要对你的数据进行任何处理
success: function (args) { //异步回调函数机制
},
});
})
</script>
</body>
def upload(request):
if request.is_ajax():
if request.method == 'POST':
password = request.POST.get('password')
username = request.POST.get('username')
print(username, password)
print(request.FILES)
return render(request, 'upload.html')
"""
wangpeng 123
<MultiValueDict: {'image': [<InMemoryUploadedFile: blog_head.jpg (image/jpeg)>]}>
"""
总结:
(1)需要用到js内置对象FormData
let formDataObj = new FormData();
添加普通的键值对:
formDataObj.append('username',$('#d1').val())
添加文件键值对
forDataObj.append('image',$('#d3')[0].files[0]) //$('#d3')[0] js对象,.files[0]拿出文件对象
(2)需要指定两个关键性的参数
contentType:false, //不需要任何编码,django后端能够自动识别出FormData对象
processData:false, //告诉浏览器。不对数据做任何处理
(3)django后端能够直接识别到formdata对象并且能够将内部的普通键值自动解析并封装到request.POST中,文件数据自动解析并封装到request.FILES中
django自带的序列化组件
"""
需求:在前端给我获取到后端用户表里面所有的数据 并且要是列表套字典
"""
from django.shortcuts import HttpResponse
from app01 import models
from django.http import JsonResponse
from django.core import serializers
def show(request):
user_queryset = models.User.objects.all()
# user_list = []
# for user in user_queryset:
# tmp = {
# 'pk': user.pk,
# 'username': user.username,
# 'password': user.password,
# 'age': user.age,
# 'gender': user.get_gender_display()
# }
# user_list.append(tmp)
# return JsonResponse(user_list, safe=False, json_dumps_params={'ensure_ascii': False})
# 序列化
res = serializers.serialize('json', user_queryset)
"""会自动帮你将数据变成json格式的字符串 并且内部非常的全面"""
return HttpResponse(res)
对于前后端分离的项目,作为后端开发的我们需要写一个接口文档,告诉前端每个字段代表的含义。
[{
"model": "app01.user",
"pk": 1,
"fields": {
"username": "tank",
"password": "1234",
"age": 30,
"gender": 2
}
}, {
"model": "app01.user",
"pk": 2,
"fields": {
"username": "jason",
"password": "dbj444",
"age": 18,
"gender": 1
}
}, {
"model": "app01.user",
"pk": 3,
"fields": {
"username": "egon\u5927\u5e05\u903c",
"password": "hecha",
"age": 66,
"gender": 1
}
}]
在线校验json格式的网站:https://www.sojson.com/
ajax结合sweetalert完成删除的二次确认
{% block js %}
<script>
$("tbody").on("click", '.del', function () { /*事件的委托,tbody内的所有".del"类按钮*/
let $aEle = $(this);
swal({
title: "你确定要删了吗?",
text: "一旦删除就找不回来了!",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "确认",
cancelButtonText: "取消", //修改cancel显示的
closeOnConfirm: false,
closeOnCancel: false,
showLoaderOnConfirm: true //加载等待时间的显示页面
}, function (isConfirm) {
if (isConfirm) {
//朝后端发送ajax请求
$.ajax({
{#url:"/app01/book/{{ user.phone }}/" + currentBtn.attr('delete_id'), // 1 传递主键值方式1#}
url: "{% url 'app01:book' user.phone %}",
type: "post",
data: {"delete_id": $aEle.attr("delete_id"), 'csrfmiddlewaretoken': '{{ csrf_token }}'},// 2 放在请求体里面
success: function (args) { //当后端给你返回结果的时候会自动触发 args接受后端的返回结果
let dataObj = $.parseJSON(args);
if (dataObj.code === 200) {
// 1.lowb版本 直接刷新当前页面
{#window.location.reload()#}
// 通过DOM操作 动态刷新
// 将被点击的删除按钮所在的那一行直接从DOM树中删掉
$aEle.parent().parent().remove();
swal("删掉了!", "赶紧回去收拾行李吧,准备跑路!", "success");
} else {
swal("发生了未知的错误", "估计是有bug了", "info");
}
}
});
} else {
swal("怂逼", "不要说我认识你", "error");
}
});
})
</script>
{% endblock %}
"""
def post(self, request, phone):
if request.is_ajax():
time.sleep(3)
delete_id = request.POST.get('delete_id')
models.Book.objects.filter(pk=delete_id).delete()
return HttpResponse(json.dumps({'code': 200}))
"""
批量插入操作
models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=64,verbose_name='书名')
views.py
这个不建议使用
from django.shortcuts import render, HttpResponse, redirect
from app01 import models
def get_book(request):
# for循环插入1000条数据
for i in range(1000):
models.Book.objects.create(title='第%s本书'%i)
# 将插入的数据再查询出来
book_queryset = models.Book.objects.all()
return render(request,'get_book.html',locals()) # 将查询出来的数据传递给html页面
上述代码书写完毕后启动django后端,浏览器访问,会发现浏览器会有一个明显的卡顿等待时间,这不是你的浏览器有问题也不是网速有问题,而是后端再不停的操作数据库,耗时较长,大概需要等待一段时间之后才能正常看到刚刚插入的1000条数据,很明显这样操作数据库的效率太低,那有没有一种方式是专门用来批量操作数据库的呢?
bulk_create()方法
强烈建议使用
def get_book(request):
# for循环插入1000条数据
book_list = []
for i in range(10000):
# models.Book.objects.create(title='第%s本书' % i)
book_list.append(models.Book(title='第%s本书' % i))
models.Book.objects.bulk_create(book_list)
# 将插入的数据再查询出来
book_queryset = models.Book.objects.all()
return render(request, 'get_book.html', locals()) # 将查询出来的数据传递给html页面
bulk_create方法是django orm特地提供给我们的方便批量操作数据库的方式,效率非常高!
自定义分页器的推导
自定义分页器的关键
(1)get请求也是可以携带参数的;
(2)queryset对象是支持索引取值和切片操作的,但是不支持负数索引
(3)内置方法divmod
100页要分几页?10页
99页要分几页?10页
101页要分几页?11页
>>> divmod(100,10)
(10, 0)
>>> divmod(99,10)
(9, 9)
>>> divmod(101,10)
(10, 1)
>>>