django练手(二十):图标上传页面增加分页的功能
一、思路
- 前端使用bootstrap的分页组件;
- 后端使用django自带的分页功能。
二、前端功能实现
-
bootstrap文档上复制分页代码,粘贴到app-templates-app-avatar.html的合适位置。复制的地址是https://v3.bootcss.com/components/#pagination 具体的代码是:
<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> -
修改后台的图标上传视图,增加分页功能
要修改的文件是:app-views-app-account.py。视图名称是:avatar_upload。具体的代码如下:# 图标上传 @login_required def avatar_upload(request): if request.method == 'GET': # 获取所有的用户图标数据 avatars = Avatar.objects.filter().all().order_by('-id') # 注意:Paginator查询集能处理的queryset必须是有序的 paginator = Paginator(avatars, 12) # 获浏览器传递的取页码数 page_num = request.GET.get('page_num', '') # 如果page_num非空且page_num字符串只有数字构成。方法isnumeric() 检测字符串是否只由数字组成。这种方法是只针对unicode对象。 if page_num is not None and page_num.isnumeric(): page_num = int(page_num) else: page_num = 1 if page_num not in paginator.page_range: page_num = 1 avatars = paginator.page(page_num) # page_range = paginator.page_range # 下一行的new_page_range方法是我自己写的一个小工具。其功能是在分页数据量很大的情况下,始终保持页面上显示的页码数是10。这个小工具的代码见下一部分。 page_range=new_page_range(page_range,page_num) return render(request, 'app/avatar.html', {"avatars": avatars, "page_range": page_range}) if request.method == "POST": # 1、判断文件路径是否存在,如果不存在,生成文件路径。 image_folder_path = os.path.join(settings.MEDIA_ROOT, 'image', 'avatar') # 文件路径 image_folder_path_exists = os.path.exists(image_folder_path) # 判断文件路径是否存在 # 如果不存在,则生成文件路径 if not image_folder_path_exists: os.makedirs(image_folder_path) # 获取所有上传的图标 file_list = request.FILES.getlist('avatar_upload') if file_list: for file in file_list: # 1、把文件名替换成整个系统唯一的文件名。 name = uuid_name(file.name) # 2、获取文件中文名 title = os.path.splitext(file.name)[0] # 3、文件存储的位置。 file_path = image_folder_path + '\\' + name # 4、把文件写入硬盘 with open(file_path, 'wb', ) as f: for part in file.chunks(): f.write(part) # 内容块写入文件 f.flush() # 清除内存 # 5、生成存储在数据库里的路径。 database_path = 'uploads/image/avatar/' + name # 6、把文件信息写入数据库 avatar = Avatar() avatar.title = title avatar.img_url = database_path avatar.save() return JsonResponse({"status": True, }) -
当分页数据很多的情况下,始终维持前台显示的页码数为10的小工具。
代码如下:from django.core.paginator import Paginator def new_page_range(page_range, page_num): """ 这是一个重写的分页功能。改写了page_range。在分页数据量很大的情况下,始终保持页面上显示的页码数是10。 page_range:分页的页码列表 page_num:页码数 返回的page_range是一个始终有10个分页的range对象 """ page_rage_len = len(page_range) if page_rage_len > 10: if page_num > 5: if page_num + 5 <= page_rage_len: page_range = range(page_num - 5, page_num + 5) return page_range if page_num + 5 > page_rage_len: page_range = range(page_rage_len - 10, page_rage_len) return page_range if page_num <= 5: page_range = range(1, 11) return page_range else: return page_range -
修订bootstrap上复制的代码,把后台传到前台的数据展示出来
修订后的代码如下:{% extends 'app/layout/basic.html' %} {% block css %} <style> .thumbnail { width: fit-content; height: fit-content; } </style> {% endblock %} {% block content %} <div class="container-fluid"> <!--图片显示的代码开始--> <div class="row" id="avatar"> <div id="avatar_child"> {% for avatar in avatars %} <div class="col-sm-6 col-md-2"> <div class="thumbnail"> <img src="../../../{{ avatar.img_url }}" alt="{{ avatar.title }}" class="img-responsive"> <div class="caption"> <h5>{{ avatar.title }}</h5> <p><a href="#" class="btn btn-primary btn-sm" role="button">Button</a> <a href="#" class="btn btn-default btn-sm" role="button">Button</a> </p> </div> </div> </div> {% endfor %} </div> </div> <!--图片显示的代码结束--> <!--分页的代码开始--> <div class="row" style="text-align: center"> <nav aria-label="Page navigation"> <ul class="pagination"> {% if avatars.has_previous %} <li> <a href="{% url 'app:avatar_upload' %}?page_num={{ avatars.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">上一页</span> </a> </li> {% endif %} {% for num in page_range %} <li><a href="{% url 'app:avatar_upload' %}?page_num={{ num }}" class="active">{{ num }}</a></li> {% endfor %} {% if avatars.has_next %} <li> <a href="{% url 'app:avatar_upload' %}?page_num={{ avatars.next_page_number }}" aria-label="Next"> <span aria-hidden="true">下一页</span> </a> </li> {% endif %} </ul> </nav> </div> <!--分页的代码结束--> <div class="row"> <!-- 上传文件的form。 action:后台的地址; method:发送的方式。上传文件一般用post方式发送; enctype:即encode type的缩写。意思是编码方式。 multipart/form-data 代表form数据有多种编码方式。 --> <form name="file" method="post" action="{% url 'app:avatar_upload' %}" enctype="multipart/form-data" id="form_upload"> {% csrf_token %} <!-- 上传文件的input标签。 type的参数必须是file,代表上传文件。 accept表示允许上传的文件类型。"image/*"代表所用图片类型。 multiple 表示一次可以传多个文件。没有这个参数一次只能上传一个文件。 required 表示在提交前必须选择一个文件 --> <input type="file" accept="image/*" name="avatar_upload" id="input_upload" multiple required> <input type="button" value="上传" class="btn btn-default btn-custom" id="btn_upload"> </form> </div> </div> {% endblock %} {% block js %} <script> $("#btn_upload").click( function () { // 实例化一个FormData对象。这个对象包含form的内容。这个数据作为后面ajax上传的数据使用。 let formData = new FormData($("#form_upload")[0]); // 获取input中上传的内容,类型为FileList let files = $("#input_upload")[0].files; // 定义一个数组,用来存储图片大小大于10000b的图片名称 let exceedArr = []; // files.length==0,表示FileList的长度为0,即没有选择图片。则提示没有选择图片,否则通过ajax进行上传动作。 if (files.length === 0) { alert("你没有选择图片"); } else { //依次获取上传图片的大小,如果10000b,则把这个图片的名称存到数组里 for (let i = 0; i < files.length; i++) { if (files[i].size > 40000) { exceedArr.push(files[i].name); } } /* 1、如果数组的长度大于0,则把数组中所用的图片名称拼接成一个字符串,并提示用户那些图片的大小超过了,同时清空文件选择控件。 2、如果数组的长度不大于0,则执行上传动作。上传完成后清空文件控件。 */ if (exceedArr.length > 0) { let alertStr = ''; for (let i = 0; i < exceedArr.length; i++) { alertStr = alertStr + exceedArr[i] + ","; } alert(alertStr + " 大于10000b,请重新选择"); $("#input_upload").val(""); } else { $.ajax({ url: "{% url 'app:avatar_upload' %}", //请求路径 type: 'POST', // 请求类型 data: formData, // 请求数据 dataType: "JSON", // 返回数据格式 contentType: false, //表示不处理数据 processData: false,//默认为true,表示会序列化数据。这里设置为false,表示不会序列化数据。 cache: false, success: function (res) { if (res.status) { $("#input_upload").val(""); //清空选择控件的内容 $("#avatar_child").load(location.href + " #avatar_child>*", ""); //起局部刷新<div>的作用 } }, error: function (res) { console.log(res); } }); } } } ) </script> {% endblock %}
四、 功能截图

本节代码已上传至gitee.com。仓库地址是:https://gitee.com/yanfenglucky/bokeyuan

浙公网安备 33010602011771号