Django搭建网络相册:批量上传文件
5038 views, 2023/10/17 updated Go to Comments
虽然 Django 自带的后台已经能够上传图片了,但是默认只能单张上传。如果你照片比较多,实在是有点不方便。
现在让我们来试着实现批量上传图片的功能。
后端代码
上一章讲过 GET 和 POST 请求的区别。图片上传会修改服务器资源,因此应该用 POST 请求。
又鉴于 home()
视图函数已经肩负用户登录功能了,如果图片上传也在里面处理,会显得太乱。
因此在 /photo/views.py
里新写一个 upload()
视图,专门用来处理文件上传。
修改内容如下:
# /photo/views.py
...
from django.shortcuts import render, redirect
...
def upload(request):
if request.method == 'POST' and request.user.is_superuser:
images = request.FILES.getlist('images')
for i in images:
photo = Photo(image=i)
photo.save()
return redirect('home')
和前面的用户名、密码这类普通的字符串数据不同,图片这类二进制文件数据在 request
中有专门的地方存放,即 request.FILES
了。因为图片可以是批量上传,所以是类似列表的有序集合,用 .getlist('images')
将此集合取出。
接下来就简单了。迭代这个图片列表,将它们全部都保存到模型中。调用 photo.save()
方法将其存储到数据库。
最后,upload()
视图并没有返回响应体,而是跳转到 home()
视图去了,继续执行 home()
视图中的代码了。参数 'home'
对应之前章节定义的 path(... name='home')
这个路径名。
接着例行惯例,需要给视图函数配置一个路径:
# /photo/urls.py
...
from photo.views import home, upload
...
urlpatterns = [
...
path('upload/', upload, name='upload'),
]
接着去修改模板中的代码。
前端代码
上一章我们已经给上传文件预留了一个 “+” 号作为入口。
余下的工作就是将这个 “+” 号变成模态窗。
修改 header.html
模板:
<!-- /templates/header.html -->
<!-- 导航栏 -->
<nav class="navbar ...">
<div class="container">
...
<!-- 修改登录模态窗链接 -->
{% if user.is_superuser %}
<ul class="navbar-nav">
<li class="nav-item">
<h2>
<a
class="nav-link active"
href="#"
data-bs-toggle="modal"
data-bs-target="#upload"
>
+
</a>
</h2>
</li>
</ul>
{% endif %}
</div>
</nav>
<!-- 模态窗相关代码 -->
{% if user.is_superuser %}
...
<!-- 新增上传模态窗 -->
<div class="modal fade" id="upload">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<h5 class="modal-title">上传图片</h5>
<form action="{% url 'photo:upload' %}"
method="post"
enctype="multipart/form-data"
>
{% csrf_token %}
<div class="col py-2">
<input
class="form-control"
type="file"
id="images"
name="images"
multiple="multiple"
accept="image/*"
>
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
</div>
{% else %}
...
{% endif %}
"+" 号通过超链接,作为触发模态窗的按钮。之所以还是考虑用模态窗的形式,是因为上传表单的信息量太小,没必要做页面的跳转。
让我们仔细看看上传文件表单的构造。
首先看 <form ...>
标签里的东东:
action="{% url 'photo:upload' %}"
指定此表单提交的路径。再次注意看它是如何和 url 路径的名称对应的。method="post"
说明这是个 POST 请求的表单。enctype="multipart/form-data"
指定表单的编码方式(将文件以二进制上传),必须有它才能正常上传文件。
再看 <input ... >
标签里:
type="file"
表示这是个文件上传控件。name="images"
注意它要和后端代码的.getlist('images')
的参数对应。multiple="multiple"
表示支持多文件上传。accept="image/*"
文件类型为图片。
欧了,测试。
测试
刷新页面,点击加号:
接下来就简单了,点击控件,随意选定多个图片,再点击提交按钮,图片就上传成功了。
总结
图片上传本身并不难,难的是对其进行安全的处理:
- 如何裁剪图片尺寸?
- 如何限制图片类型?
- 如何判断图片里是否带有病毒?
- 如何确保用户没有上传奇怪的小电影截图?
个人相册还好说,操作资源就自己,不会瞎折腾。但如果你要开发论坛或平台,这些都是要好好考虑的。
另一个现实的问题是,云服务器资源是昂贵的,作为草根网站,你的服务器带宽根本支撑不起庞大的图片流量。用户会在你的站点卡得吐血。教程末尾章节将会解决这个问题,在此之前,下一章先聊聊分页。
点赞 or 吐槽?评论区和我聊!