Django之文件上传
Django项目中,文件上传有自己的方法,我们先以python常规读写文件的方法来操作。需要注意的是不管后端怎么写,前端html页面中必须定义enctype='multipart/form-data'才可以上传文件,如下
<form action="" method = 'post' enctype='multipart/form-data'>
<input type="file" name = 'myfile'>
</form>
普通python方式接收上传文件,下例with open语句写在for循环里也是可以的,但是考虑到打开关闭文件的开销,建议不要这样。默认文件会上传至项目的根目录下
class FileDemo(View):
...
def post(self, req):
myfile = req.FILES.get('myfile')
# 这里为什么要以ab或者wb打开新文件,是因为chunk是一个bytes类型,
# 如果是a或者w,文件指针fp写入的必须是str类型的数据
with open('b.txt', 'ab') as fp:
for chunk in myfile.chunks():
print(type(chunk))
fp.write(chunk)
return HttpResponse('success')
文件上传进阶,利用Django的模型来处理上传文件,我们定义一个模型Articles,属性upload_file 用于接收文件类型(FileField),upload_to用于定义文件上传所在地(相对目录),如果写成upload_to='%Y/%m/%d'即将文件上传至年月日三级目录下(将文件分类保存有助检索)
class Articles(models.Model):
title = models.CharField(max_length=100)
content = models.CharField(max_length=10)
upload_file = models.FileField(upload_to='uploadFolder')
视图层代码,需要注意文件获取是req.FILES:
class FileDemo2(View):
...
def post(self, req):
title = req.POST.get('title')
content = req.POST.get('content')
myfile = req.FILES.get('myfile')
Articles.objects.create(title= title, content= content, upload_file= myfile)
return HttpResponse('success')
好处是我们不用再写文件的处理方法,保存到数据库里面是这么个东西,如果文件存在,会自动重命名
我们还可以配置默认的文件保存目录,类似之前的静态文件目录static,在settings.py中,配置文件保存目录及公共访问的url
MEDIA_ROOT = 'media'
MEDIA_URL = 'media/'
配置了MEDIA_ROOT 之后,默认的文件保存路径变成了media/uploadFolder,即upload_to定义的目录变为第二级目录,而如果我们想通过公共url访问文件,还需要在urls.py中定义相关文件的访问路径。
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.FileDemo2.as_view()),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
如果我们想要限制上传的文件后缀,就需要利用表单来处理了。首先在模型中定义了验证器,并定义了错误信息提示message,当然我们在表单中也是可以定义错误信息提示,而且会覆盖模型中的message
# models.py
from django.core import validators
class Articles(models.Model):
title = models.CharField(max_length=100)
content = models.CharField(max_length=10)
upload_file = models.FileField(upload_to='%Y/%m/%d', validators=[validators.FileExtensionValidator(allowed_extensions=['png','txt'],message='errors')])
利用ModelForm更为便捷,所以我们可以新建forms.py,这里需要注意的是,模型表单中的fields = "__all__",即应用的是模型中的所有字段,而模型models.py中关于文件这个字段我命名为upload_file,而前端html页面中的我定义的type=‘file’的name = 'myfile',所以我还需要将前端页面中上传文件name属性修改成模型名称name = 'upload_file',否则在验证表单时将会一直是invalid!
class FileForm(forms.ModelForm):
class Meta:
model = Articles
# fields = ("",)
fields = "__all__"
error_messages = {
'upload_file':{
'invalid_extension':'不可用的后缀'
}
}
视图层代码,采用forms.save()和使用req.POST获取的数据是一致的:
class FileDemo3(View):
...
def post(self, req):
forms = FileForm(req.POST, req.FILES)
if forms.is_valid():
# title = req.POST.get('title')
# content = req.POST.get('content')
# myfile = req.FILES.get('upload_file')
# Articles.objects.create(title= title, content= content, upload_file= myfile)
forms.save()
return HttpResponse('success')
...