创建模型
首先先进入我们的testsite
项目下,打开members/models.py
文件,先添加我们保存文件的数据模型:
class Document(models.Model): name = models.CharField(max_length=255) file = models.FileField(upload_to='uploads/') # 'uploads/' 是文件上传的相对路径 uploaded_at = models.DateTimeField(auto_now_add=True)
这里的文件存储目录可以自定义我们需要存储文件的目录,也可以在我们的 env文件
做配置,这里直接读取相应的配置 env字段
就可以了。
进入testsite
根目录执行更新迁移文件命令,这一步前面有说到,是为了更新迁移文件。
py manage.py makemigrations
可以看到我们的migrations
目录增加了新的迁移文件
执行迁移
py manage.py migrate
我们新增加的文件模型表就在数据库生成好了。
使用模型
进入testsite/members
目录,新增form.py
表单文件,这里会定义文件上传的字段。
from django import forms from .models import Document class UploadFileForm(forms.ModelForm): class Meta: model = Document fields = ['name', 'file'] # 包含你想要用户填写的字段
接下来将上传的文件绑定到表单中,打开testsite/members/views.py
视图文件:
from .forms import UploadFileForm #需要我们引入上一步建立好的表单文件 def upload_file(request): if request.method == "POST": form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): form.save() # 保存表单数据到数据库 return HttpResponse("上传成功") else: form = UploadFileForm() return render(request, "polls/upload.html", {"form": form})
我们传递request.FILES
到表单的构造函数;这就是文件数据绑定到表单的方式。
请注意,request.FILES
仅当请求方法为POST
,实际发送了至少一个文件字段且<form
>表单有发送请求的并且具有enctype="multipart/form-data"
属性时。否则request.FILES
将为空。
最后一步,添加上传页面,进入members/templates/members
目录,新增upload.html
文件,注意跟我们的视图里面指向的文件名保持一致。
<form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form>
打开地址http://127.0.0.1:8000/polls/upload/
进入文件上传页面
点写完表单点击提交
这个时候我们的文件上传就完成了,可以打开我们的testsite
目录,进入我们设置的uploads
目录,就看到我们上传好的文件:
然后我们再打开数据库,进入模型对应的members_document
表,也可以看到文件上传生成的数据。
批量上传
为了使用一个表单字段上传多个文件,创建该字段的子类并将其allow_multiple_selected
类属性设置为True
。
进入表单文件forms.py
:
class MultipleFileInput(forms.ClearableFileInput): allow_multiple_selected = True class MultipleFileField(forms.FileField): def __init__(self, *args, **kwargs): kwargs.setdefault("widget", MultipleFileInput()) super().__init__(*args, **kwargs) def clean(self, data, initial=None): single_file_clean = super().clean if isinstance(data, (list, tuple)): result = [single_file_clean(d, initial) for d in data] else: result = [single_file_clean(data, initial)] return result class FileFieldForm(forms.Form): file_field = MultipleFileField()
然后进入view.py
视图文件重写子类form_valid()
的方法 FormView
来处理多个文件上传:
from .forms import FileFieldForm # 确保导入正确的表单定义 from .models import Document # 引入Document模型 def batch_upload_view(request): if request.method == 'POST': form = FileFieldForm(request.POST, request.FILES) if form.is_valid(): # 获取表单中title的值 title = form.cleaned_data['title'] # 处理文件上传 for file in request.FILES.getlist('file_field'): document = Document(file=file, name=title) # 假设title作为文件的名称或描述 document.save() return HttpResponse("上传成功") else: # 请求方法为GET时,初始化表单 form = FileFieldForm() return render(request, "polls/uploads.html", {"form": form})
假如你不想使用模型关联上传,则使用如下方式:
from django.core.files.storage import default_storage #使用默认存储引擎保存文件 file_name = default_storage.save(file.name, file)
然后重新渲染我们的批量上传页面,跟我们的forms django
表单关联
<form method="post" enctype="multipart/form-data"> <!-- enctype 必须为 multipart/form-data 以支持文件上传 --> {% csrf_token %} <!-- Django表单必须的安全令牌 --> {{ form.title }} {{ form.file_field }} <!-- 渲染文件上传字段,MultipleFileField将会生成相应的input元素 --> <button type="submit">上传文件</button> </form>
上面的 csrf_token
django
表单必须的安全令牌,form.file_field
也是我们form.py
定义的批量上传字段。
打开members/urls.py
,添加我们的路由
path('uploads/', views.batch_upload_view, name='upload'),
我们的批量上传功能就已经写好了,我们打开http://127.0.0.1:8000/polls/uploads/
页面
填好表单,批量选择文件,点击上传,这里我只是演示,没有做页面渲染样式与字段验证,感兴趣的小伙伴可以加上自己喜欢的样式。
然后进入我们的数据库可以看到我们与上传模型的记录被添加
我们打开uploads
目录,也可以看到我们上传好的文件。
需要注意的是在保存上传的文件之前,数据需要存储在某个地方。
默认情况下,如果上传的文件小于 2.5 MB
,django
会将上传的全部内容保存在内存中。
这意味着保存文件仅涉及从内存读取和写入磁盘,因此速度非常快。
但是,如果上传的文件太大,django
会将上传的文件写入存储在系统临时目录中的临时文件。
例如/tmp/tmpzfp6I6.upload
。如果上传的文件足够大,您可以看到该文件的大小随着 django
将数据传输到磁盘而增长
总结
文件上传算是一种很常见的需求,几乎构建很多项目系统,以及插件都需要用到。
通过上面例子可以看到django
通过forms
表单的形式灵活定义文件上传的页面,字段,以及数据库存储。
在实际项目中我们还要考虑到安全性,包括检查文件大小(可通过FileField
的max_length
属性设置)、防止路径遍历攻击。
还需注意服务器端的验证,比如检查文件类型、内容安全等。
例子里面有提到,django
的FileSystemStorage
和DefaultStorage
类提供了基本的文件存储管理。
自定义存储后端可以提供更多灵活性,如自定义文件命名规则、存储路径等,以避免文件名冲突和优化组织结构。
大量文件上传或下载也会影响应用性能。最好采用云存储服务、内容分发网络(CDN
)、以及对静态和媒体文件的有效缓存策略,可以显著提升用户体验。
对于我们本地的存储策略,需要考虑上传文件的生命周期管理,包括旧文件的定期清理策略,以避免无限制增长占用存储空间。