How to Restrict Uploaded File Extensions
To restrict the types of files users can upload, use the FileExtensionValidator class. This validator ensures that the extension of an uploaded file matches a predefined list of allowed extensions.
Restricting Extensions in Models
The most common way to enforce file type restrictions is by adding the validator directly to a FileField in your model.
from django.db import models
from django.core.validators import FileExtensionValidator
class Document(models.Model):
# Only allow PDF and Word documents
pdf_file = models.FileField(
upload_to='documents/',
validators=[FileExtensionValidator(allowed_extensions=['pdf', 'docx'])]
)
When a user attempts to upload a file with an extension not in the list (e.g., image.png), the validator will raise a ValidationError.
Restricting Extensions in Forms
You can also apply the validator at the form level. This is useful if you want to apply different restrictions to the same model field in different contexts.
from django import forms
from django.core.validators import FileExtensionValidator
class UploadForm(forms.Form):
archive = forms.FileField(
validators=[FileExtensionValidator(allowed_extensions=['zip', 'tar.gz'])]
)
Validating Image Extensions
For image-specific uploads, the codebase provides a specialized helper function validate_image_file_extension. This function automatically allows all extensions supported by the installed version of the Pillow library.
from django import forms
from django.core.validators import validate_image_file_extension
class ProfileForm(forms.Form):
avatar = forms.FileField(validators=[validate_image_file_extension])
In django/forms/fields.py, the ImageField class uses this validator by default:
class ImageField(FileField):
default_validators = [validators.validate_image_file_extension]
Customizing Error Messages
You can customize the error message and the error code returned when validation fails by passing them to the FileExtensionValidator constructor.
from django.core.validators import FileExtensionValidator
validator = FileExtensionValidator(
allowed_extensions=['pdf'],
message="Only PDF files are permitted for this upload.",
code="unsupported_file_type"
)
The default message uses placeholders for the actual extension and the list of allowed extensions:
"File extension “%(extension)s” is not allowed. Allowed extensions are: %(allowed_extensions)s."
Key Implementation Details
- Case Insensitivity: The validator automatically converts both the provided
allowed_extensionsand the uploaded file's extension to lowercase before comparison. - Name-Based Validation: As seen in
django/core/validators.py, the validator relies on thenameattribute of the file object:def __call__(self, value):
extension = Path(value.name).suffix[1:].lower()
if (
self.allowed_extensions is not None
and extension not in self.allowed_extensions
):
# ... raises ValidationError - Security Warning: This validator only checks the file extension string. It does not inspect the actual file content (magic bytes). For higher security, combine this with content-based validation or use
ImageFieldfor images, which performs additional content verification in itsto_pythonmethod. - Empty Lists: If
allowed_extensionsis not provided or isNone, the validator will allow all file extensions.