![d16886f0cf9d943497f65924d4014dea.png](https://i-blog.csdnimg.cn/blog_migrate/02d33fd954e999be0373478164d235e8.jpeg)
昨晚一股劲上头弄到了凌晨1点,今早到了公司才想起来代码还没传到Github上,果然人太困了做啥都是丢三落四的,今晚回家得赶紧备份上。
这次做的内容相对于之前的内容来说算是一次大更新,在我还没忘记之前得赶紧记下来。除了文件上传,还有输入框的调整也花了很多心思,有时间还得再开一篇接着写。
首先,说一下自己的操作环境: Django 2.2, Python 3.5
理解一下Django的文件传输步骤:
- 本地用户在网页的表单选择文件
- 被选择的文件会以非加工处理的方式传至服务器
- 在服务器端生成TemporaryUploadedFile形式的数据(储存在类似于
/tmp/tmpzfp6I6.upload
的位置,此时可以对数据进行加工) - 最后TUF形式的数据被转换成实体数据存放在指定位置
这次我是没有在Model文件里添加ImageField,这样做的原因一个是节省数据库的空间,不想破坏现有的结构,另一个就是一个帖子对应多个图片,不知道ImageField支不支持链接多个图片。不过这样的操作是不推荐的,因为要控制用户上传的文件类型什么的就很麻烦,还在找更好的方法,如果有好方法也欢迎留言讨论。
接着就是代码。很多教程里面都提到了在setting.py里面添加[MEDIA_ROOT="media"]的步骤,但如果你没有在Model.py里面加FileField,或者不方便加,其实可以省掉改Setting.py文件的这个步骤。
这样,直接在Form.py里面添加:
from django import forms
class UploadFileForm(forms.Form):
File_upload = forms.FileField()
但这个只能上传一个文件,想要上传多个文件的话,可以这么写:
from django import forms
class UploadFileForm(forms.Form):
File_upload = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
括号里面添加的 multiple 就是允许上传条上传多个文件的属性。
然后在html里加入表单:
<form enctype="multipart/form-data" method="post" action="文件上传位置">
{{ form.File_upload }}<!--可以对表格随意更改,比如用django-widget-tweaks什么的-->
</form>
这样一个基本的文件上传条就加好了。如果要自定义文件储存位置的话action可以省略,后面我们自己处理。要注意的是 enctype 和 method 两个属性不可缺少,不然文件无法跟表格绑定,提交表格的时候文件无法一起提交上去。
在Django模型组里面,ImageField属于FileField系列,所以想要上传图片的时候可以直接把FileField替换成ImageField。
如果我们做的是一个表格组,除了上传文件之外还有别的表单数据的话,可以把这两个属性加在html里最外面的Form属性上,比如:
<form enctype="multipart/form-data" method="post" action="文件上传位置">
{{for field in form}}<!--用form.py做个集合-->
....
{{ endfor }}
</form>
然后接下来就是对View.py文件的修改,先贴一段Django官方的代码,然后我慢慢解释:
from .forms import UploadFileForm
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES) # 比起平常的提交表格多了request.FILES
if form.is_valid():
handle_uploaded_file(request.FILES['file']) # 这个位置可以替换成别的写法
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
# 这段是后面要讲到的
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
用Django做过普通Form的人对
form = UploadFileForm(request.POST, request.FILES)
这句很眼熟,因为一般表单的数据都这么处理:
form = UploadFileForm(request.POST)
后面加上 request.FILES 就成了上传文件时用到的格式 ,至于要将文件保存下来,则需要 write 或 save 函数。
也就是
handle_uploaded_file(request.FILES['file']) # 这个位置可以替换成别的写法
可以写成
request.FILES['file'].save()
这样上传的文件会直接储存到你指定的位置。但直接这样写会有一个缺点,那就是当文件比较大的时候,特别占用服务器的内存(参照传输步骤的第三步,服务器会生成一个临时文件),尤其是当你架构一个网站,有那么多人同时上传文件的话,说不定服务器内存不够就直接down了。
所以这时候上传文件的Handle就派上了用场。
以官网的代码为例:
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
这个函数就是上传文件的Handle函数,这个函数里面将一个file分解成了chunk。可以想象成一把刀把一个大文件切成了小块,然后一块一块的写入储存。Django提供了很好的扩展性,我们可以自己定义这个chunk的大小(一个chunk的初始值为64KB)
(接下来慢慢补充对于上传文件Handle的处理,etc)