Django文件上传:文件名未保存

2 投票
3 回答
4936 浏览
提问于 2025-04-16 10:52

我正在上传文件,并把一些信息存储在数据库里。其中一部分信息就是文件名。但是,不知道为什么,文件名似乎没有被保存下来!我会把我认为相关的代码部分贴出来,尽量简短。

class UploadFile(models.Model):
   ...
    theFile = models.FileField(upload_to = "Genius/Uploads/", null = True)
    filename = models.CharField(max_length = 50, blank = True, null = False)

class UploadFileForm(ModelForm):
    class Meta:
        model = UploadFile
        fields = ('title', 'theFile', 'date_uploaded',) # Don't prompt for filename


def files_upload(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            form.filename = request.FILES['theFile'].name # TODO: sanitize!
            # form.filename = 'foo'
            form.save()
            return HttpResponseRedirect('/files/upload/successful/')
        else:
            form = UploadFileForm()
        return render_to_response('files/upload_file.html', { 'form': form })

我在保存表单之前和之后检查过request.FILES['theFile'].name的值。出于某种原因,它的值是完整的,但就是没有存进数据库里。

3 个回答

0

我想补充一点,以后你可以尽量避免在模型表单中放置这样的业务逻辑。虽然WoLpH的回答是正确的,并且很好地展示了如何通过ModelForm处理额外的模型实例,但在某些情况下,字段之间的数据依赖关系应该通过ModelFormModelForm的各自clean()方法来处理,这在官方文档的多个地方都有提到(这里有一篇关于表单的说明,ModelModelForm的API也是一样的)。

在你的情况下,这意味着:

import os

class UploadFile(models.Model):

     # ...

     def clean(self):
          # Field data has already been populated by this point.
          # Note that `FieldFile` inherits from `File` and that
          # `File.name` is actually the full path to the file
          # so we need to get the base path component sans the extension

          path, extension = os.path.splitext(self.thefile.file.name)
          self.filename = os.path.basename(path)

就这样!如果你正确设置了模型字段的editable属性,你会发现可以依赖Django自动为UploadFile模型生成ModelForm。这意味着你不需要为通用的创建、更新视图或模型的ModelAdmin定义ModelForm,这样可以减少需要管理的代码行数!

一般来说,建议你在覆盖默认行为时多考虑一下,是否真的有必要,尤其是在处理业务逻辑的最末端,否则你可能会遭遇意想不到的问题。

1

表单字段的值不是通过表单的属性来访问的。所以,设置 'form.filename' 并不会把值放到 filename 这个字段里。正确的方法是,在调用 form.save() 后,直接在返回的实例上设置这个值。

upload_file = form.save(commit=False) 
upload_file.filename = filename
upload_file.save() 
2

这是因为 form.filename 是表单中的一个字段,而不是它将要保存的值。

你需要找的是这样的东西:

class UploadFileForm(ModelForm):
    def save(self, commit=True):
        instance = ModelForm.save(self, commit=False)
        instance.filename = self.files['theFile'].name

        if commit:
            instance.save()

        return instance

    class Meta:
        model = UploadFile
        fields = ('title', 'theFile', 'date_uploaded',) # Don't prompt for filename

另一种解决方案:

upload_file = form.save(commit=False)
upload_file.filename = request.FILES['theFile'].name
upload_file.save()

撰写回答