FileField with file extension whitelist

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import os

from django import forms


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!")

#-------------------------------------------------------------------------

if __name__ == "__main__":
    import doctest, datetime
    doctest.testmod()

More like this

  1. Validate by file content type and size by macmichael01 4 years, 3 months ago
  2. Whitelisted overwriting FileSystemStorage by nickma_at 1 year, 9 months ago
  3. Database file storage by powerfox 4 years, 3 months ago
  4. create_update for newforms (ModelForm) by Rozza 5 years, 2 months ago
  5. Custom FileField with content type and size validation by nemesis 2 years, 7 months ago

Comments

Finity (on May 23, 2011):

This will through an AttributeError if required=False. (Due to trying to access data.name when data will be None if required == False).

I rewrote it as [HTML_REMOVED] def clean(self, *args, kwargs): data = super(ExtFileField, self).clean(*args, kwargs)

    if data is None:
        if self.required:
            raise ValidationError("This file is required")
        else:
            return
    else:
        filename = data.name
        ext = os.path.splitext(filename)[1]
        ext = ext.lower()
        if ext not in self.ext_whitelist:
            file_types = ", ".join([i for i in self.ext_whitelist])
            error = "Only allowed file types are: %s" % file_types
            raise forms.ValidationError(error)

[HTML_REMOVED]

Hopefully I'm correct on this one.

#

Finity (on May 23, 2011):

s/through/raise an AttributeError exception. :)

Couldn't figure out how to keep djangosnippets from mucking up my code, but hopefully you get the point.

#

computmaxer (on February 19, 2013):

This snippet does not account for a field that is not required, and also does not return data so it does not get cleaned correctly.

The superclass will return False for data if the file has been cleared and the field is not required.

Here's a revised clean method for this snippet:

```

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 not allowed! Filetypes allowed: " + ', '.join(self.ext_whitelist))
    return data

```

#

(Forgotten your password?)