如何使用ExtFileField片段?

时间:2011-02-18 10:43:39

标签: django

由于我想将fileupload限制为某些类型的audiofiles,我发现django片段http://djangosnippets.org/snippets/977/,它将文件上传限制为扩展名白名单中的文件:

class ExtFileField(forms.FileField):
"""
Same as forms.FileField, but you can specify a file extension whitelist.

>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>>
>>> t = ExtFileField(ext_whitelist=(".pdf", ".txt"))
>>>
>>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content'))
>>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content'))
>>>
>>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content'))
Traceback (most recent call last):
...
ValidationError: [u'Not allowed filetype!']
"""
def __init__(self, *args, **kwargs):
    ext_whitelist = kwargs.pop("ext_whitelist")
    self.ext_whitelist = [i.lower() for i in ext_whitelist]

    super(ExtFileField, self).__init__(*args, **kwargs)

def clean(self, *args, **kwargs):
    data = super(ExtFileField, self).clean(*args, **kwargs)
    filename = data.name
    ext = os.path.splitext(filename)[1]
    ext = ext.lower()
    if ext not in self.ext_whitelist:
        raise forms.ValidationError("Not allowed filetype!")  

在我的表单中,我有一个标准的FileField,直到现在。上传文件,保存并完美运行。然后我像这样替换FileField

class NewItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
    super(NewItemForm, self).__init__(*args, **kwargs)
    self.fields['file']=ExtFileField(ext_whitelist=(".wav", ".aif", ".flac"))

class Meta:
    model = Item
    fields = ('file','name','meta1','tags')  

当尝试上传不在白名单中的任何文件时,我收到错误消息“Not allowed filetype!”,这很好。但是当在白名单中上传文件时,我收到错误消息“此字段不能为空。”,我不明白。我只是怀疑它与我从模型中替换文件字段的方式有关。什么是正确的方法呢?

2 个答案:

答案 0 :(得分:0)

覆盖模型表上字段的正确方法就是在类级别声明字段:

class NewItemForm(forms.ModelForm):
    file = ExtFileField(ext_whitelist=(".wav", ".aif", ".flac"))

答案 1 :(得分:0)

在'clean'方法结束时,请确保返回数据,以便form.FileField的常规clean方法可以访问它。在您当前的实现中(直接来自代码段),forms.FileField clean方法将不会获取上传的文件。

我还需要调整我的方法,因为我有不需要的字段。因此,实现将无法尝试访问数据的name属性(因为数据为None)。

最后,您可以使用内容类型(下面未显示)执行相同类型的文件白名单,而不是检查扩展名,而是检查data.file.content_type与您将传递到字段构造函数的content_whitelist参数(与ext_whitelist一样。

def clean(self, *args, **kwargs):
    data = super(ExtFileField, self).clean(*args, **kwargs)
    if data:
        filename = data.name
        ext = os.path.splitext(filename)[1]
        ext = ext.lower()
        if ext not in self.ext_whitelist:
            raise forms.ValidationError("Filetype '%s' not allowed for this field" % ext)
    elif not data and self.required:
        raise forms.ValidationError("Required file not found for %s" % self.label)
    return data