YOLO813

Django初学(8)- 文件上传

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')
         ...