day08 Django: contentType 文件上传 分页器
一.Django: settings.py
APPEND_SLASH = True : 加"斜杠" : django 如果发现浏览器请求的url,和我urls.py里面的路径只差最后一个"斜杠": 会给浏览器一个redirect,让浏览器加个"斜杠"再访问一次
APPEND_SLASH = Flase :不加"斜杠"
注意: 只适用get请求, 而post请求无法做这件事
二.Django: 图书管理系统的删除做成 ajax
<body>
<!DOCTYPE html>
{% csrf_token %}
<h1>查看书籍 !</h1>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<a href="{% url 'booksadd' %}" class="btn btn-primary btn-sm">添加书籍</a>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>编号</th>
<th>书籍名称</th>
<th>价格</th>
<th>出版日期</th>
<th>出版社</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}</td>
<td>{{ book.pub_date|date:"Y-m-d" }}</td>
<td>{{ book.publish }}</td>
<td>
<button nid="{{ book.nid }}" class="btn btn-danger btn-sm delbtn">删除</button>
<a href="{% url 'booksedit' book.nid %}" class="btn btn-warning btn-sm">编辑</a>
{#<a href="{% url 'booksdelete' book.nid %}" class="btn btn-danger btn-sm">删除</a>#}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<script>
$('.delbtn').click(function () {
var nid = $(this).attr('nid');
var tr = $(this).parent().parent();
$.ajax({
url: `/books/ajaxdelete/${nid}`,
type: 'post',
data: {
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
},
success: function (response) {
var rsp = JSON.parse(response)
if (rsp.state) {
tr.remove()
}
},
})
})
</script>
</body>
三.Django: contentType
1.发送contentType: urlencoded这种数据格式的数据, 直接发
request.POST
request.GET
request.body
user=bajie&pwd=123&a=6 #这种数据封装格式叫做: urlencoded
contentType: #浏览器告诉服务器: 请求体的数据封装格式
contentType: urlencoded #form表单和ajax默认都是是这个类型
2.发送contentType: 'json'数据格式
2.1.发送端:ajax
Django的post需要验证的token先关掉
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
{% csrf_token %}
<script>
$('.cal').click(function () {
num1 = $('#num1').val();
num2 = $('#num2').val();
$.ajax({
url: `/handle_ajax/`,
type: 'post',
contentType: 'json',
data: JSON.stringify({
num1:num1,
num2:num2,
}),
success: function (response) {
$('#num3').val(response);
}
})
})
</script>
2.2.接收端
Django 只帮我们处理 contentType = "urlencoded"类型的数据, 交给request, 其他数据类型返回空字典
json格式的请求体: 在request.body里(b'{"num1":"1","num2":"2"}'): 需要我们自己处理
def handle_ajax(request):
rsp = json.loads(request.body.decode('utf8'))
num1 = rsp.get('num1')
num2 = rsp.get('num2')
return HttpResponse(str(int(num1)+int(num2)))
四.Django: 文件上传
1.form表单的文件上传
发送enctype="multipart/form-data"数据格式
formdata格式的请求体: 在request.FILES里(<MultiValueDict: {'file_obj': [<InMemoryUploadedFile: 激活码.txt (text/plain)>]}>); 需要我们自己处理
1.1.发送端
enctype="multipart/form-data": 必须要写, 不然会按urlencoded, 请求体会取到一个文件名而已
<form action="/fileput/" method="post" enctype="multipart/form-data">
用户名<input type="text" name="user">
文件<input type="file" name="file_obj">
<input type="submit">
</form>
1.2.接收端
request.FILES: 文件使用这个来接收到
request.FILES.get('file_obj'): 取文件对象
def fileput(request):
import os
from s15ajax import settings
file_obj = request.FILES.get('file_obj')
path = os.path.join(settings.BASE_DIR, file_obj.name)
with open(file_obj.name, 'wb') as f:
for line in file_obj:
f.write(line)
return HttpResponse('ok')
2.ajax的文件上传
发送隐含的enctype="multipart/form-data"原form-data数据格式
2.1.发送端
使用js自带的构造函数FormData创建formdata对象
然后把input里面找到的文件对象,追加到formdata对象里
ajax里面发送原生的data:formdata 数据格式
<body>
<form>
用户名 <input type="text" id="user">
文件<input type="file" id="file_obj">
<input type="button" class="filebtn" value="提交">
</form>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
{% csrf_token %}
<script>
$('.filebtn').click(function () {
var user = $('#user').val();
var file_obj = $('#file_obj')[0].files[0]; //获取文件对象
var formdata = new FormData();
formdata.append("file_obj", file_obj);
formdata.append("user", user);
$.ajax({
url:`/fileput/`,
type:'post',
processData: false, //不处理数据
contentType: false, //不设置内容类型 使用原formdata数据
data: formdata,
success: function (response) {
console.log(response)
}
})
});
</script>
</body>
2.2.接收端
不变: 和form表单文件上传的接收端一样
五.Django: 分页器
1.数据库批量插入数据
方式一: for循环: 每次都一个insert,效率低
def index(request):
for i in range(100):
Book.objects.create(name='book_%s' % i, price=i*i)
方式二: 使用bulk_create()方法批量插入, 一个inset,100条value(),效率高
def index(request):
book_list = []
for i in range(100):
book = Book(name='book_%s' % i, price=i*i)
book_list.append(book)
Book.objects.bulk_create(book_list)
2.分页器的使用
from django.core.paginator import Paginator
book_list = Book.objects.all() #去数据库取记录
paginator = Paginator(book_list, 10) #先实例化
paginator.count #数据总数 100
paginator.num_pages #总页数 10
paginator.page_range #页码的列表 range(1, 11)
page = paginator.page(5) #第5页的对象, 可遍历
for i in page: #可遍历
print(i)
page.has_next() #True或False: 判断是否有上一页
page.has_previous() #True或False: 判断是否有下一页
page.next_page_number() #下页的页号
page.previous_page_number() #上页的页号
3.分页实例
3.1.views.py
from django.shortcuts import render, HttpResponse
from django.core.paginator import Paginator, EmptyPage
from app01.models import Book
def index(request):
book_list = Book.objects.all()
paginator = Paginator(book_list, 10)
try:
current_page_number = request.GET.get('page', 1)
current_page_number = int(current_page_number)
current_page = paginator.page(current_page_number)
except EmptyPage as e:
current_page_number = 1
current_page = paginator.page(1)
return render(request, 'index.html', locals())
3.2.index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<ul>
{% for book in current_page %}
<li>{{ book.name }} ---- {{ book.price }}</li>
{% endfor %}
</ul>
<nav aria-label="Page navigation">
<ul class="pagination">
{% if current_page.has_previous %}
<li>
<a href="?page={{ current_page.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for page_num in paginator.page_range %}
{% if page_num == current_page_number %}
<li class="active"><a href="/index/?page={{ page_num }}">{{ page_num }}</a></li>
{% else %}
<li><a href="/index/?page={{ page_num }}">{{ page_num }}</a></li>
{% endif %}
{% endfor %}
{% if current_page.has_next %}
<li>
<a href="?page={{ current_page.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</body>
</html>