Skip to main content

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_extensions and the uploaded file's extension to lowercase before comparison.
  • Name-Based Validation: As seen in django/core/validators.py, the validator relies on the name attribute 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 ImageField for images, which performs additional content verification in its to_python method.
  • Empty Lists: If allowed_extensions is not provided or is None, the validator will allow all file extensions.