Django cookbook · Intermediate

Validate uploads and store them in object storage

Users upload files that are too large, the wrong type, or end up on the web server's disk.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Validate size and extension in the form or serializer, store files through the STORAGES setting (S3 via django-storages), generate random names, and serve private files with short-lived signed URLs.

Solution

# settings.py
STORAGES = {
    "default": {
        "BACKEND": "storages.backends.s3.S3Storage",
        "OPTIONS": {"bucket_name": "app-uploads", "querystring_auth": True, "querystring_expire": 300},
    },
    "staticfiles": {"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"},
}
DATA_UPLOAD_MAX_MEMORY_SIZE = 5 * 1024 * 1024


# documents/models.py
import uuid

from django.core.exceptions import ValidationError
from django.core.validators import FileExtensionValidator
from django.db import models


def max_size_10mb(file):
    if file.size > 10 * 1024 * 1024:
        raise ValidationError("Files must be 10 MB or smaller.")


def upload_to(instance, filename):
    return f"documents/{instance.owner_id}/{uuid.uuid4().hex}.pdf"


class Document(models.Model):
    owner = models.ForeignKey("accounts.User", on_delete=models.CASCADE)
    file = models.FileField(
        upload_to=upload_to, validators=[FileExtensionValidator(["pdf"]), max_size_10mb]
    )
    uploaded_at = models.DateTimeField(auto_now_add=True)

Pitfalls

  • Trusting the client's file name or content type; generate names and check content when it matters.
  • Serving user uploads from the same domain as the app without Content-Disposition, enabling stored XSS.
  • Leaving orphaned files when records are deleted; delete them in a task after commit.

Variations

  • For large files, let browsers upload directly to S3 with presigned POST URLs, then confirm in Django.
  • Scan uploads for malware in a background task before marking them available.

Further reading: Managing files

Reference: https://docs.djangoproject.com/en/6.0/topics/files/

More Django recipes

Was this page helpful?