Django File Uploads

Handling file and image uploads in Django

📁 What are File Uploads?

Django makes it easy to handle file uploads from users. You can accept images, documents, videos, and any file type. Django handles validation, storage, and security automatically with simple configuration.


# Simple file upload model
from django.db import models

class Document(models.Model):
    title = models.CharField(max_length=200)
    file = models.FileField(upload_to='documents/')
    uploaded_at = models.DateTimeField(auto_now_add=True)
                                    

File Upload Types

🖼️

Images

Upload and validate image files

class Profile(models.Model):
    avatar = models.ImageField(
        upload_to='avatars/'
    )
📄

Documents

Handle PDF, Word, Excel files

class Report(models.Model):
    document = models.FileField(
        upload_to='reports/'
    )
🎵

Media

Upload audio and video files

class Song(models.Model):
    audio = models.FileField(
        upload_to='music/'
    )
📦

Archives

Handle ZIP and compressed files

class Backup(models.Model):
    archive = models.FileField(
        upload_to='backups/'
    )

🔹 Basic File Upload Setup

Configure Django to handle file uploads by setting up media files in your settings. This tells Django where to store uploaded files and how to serve them during development.

# settings.py
import os

# Media files configuration
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# urls.py
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # Your URL patterns
]

# Serve media files in development
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

🔹 Creating Upload Model

Define models with FileField or ImageField to store uploaded files. The upload_to parameter organizes files into folders automatically.

# models.py
from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
    bio = models.TextField(max_length=500, blank=True)
    
    def __str__(self):
        return f"{self.user.username}'s profile"

class Document(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    file = models.FileField(upload_to='documents/%Y/%m/%d/')
    uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
    uploaded_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.title

File Storage Structure:

media/avatars/user_photo.jpg

media/documents/2024/01/15/report.pdf

🔹 Creating Upload Form

Use Django forms to handle file uploads with validation. ModelForm automatically creates form fields based on your model definition.

# forms.py
from django import forms
from .models import Document, UserProfile

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ['title', 'description', 'file']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
            'file': forms.FileInput(attrs={'class': 'form-control'}),
        }

class ProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['avatar', 'bio']

🔹 Handling Upload in Views

Process file uploads in views using request.FILES. Always use POST method and include enctype in your form for file uploads to work properly.

# views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import DocumentForm
from .models import Document

@login_required
def upload_document(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            document = form.save(commit=False)
            document.uploaded_by = request.user
            document.save()
            return redirect('document_list')
    else:
        form = DocumentForm()
    
    return render(request, 'upload.html', {'form': form})

def document_list(request):
    documents = Document.objects.all().order_by('-uploaded_at')
    return render(request, 'documents.html', {'documents': documents})

🔹 Upload Template

Create an HTML form with enctype="multipart/form-data" to enable file uploads. This encoding type is required for sending files to the server.

<!-- upload.html -->
<h2>Upload Document</h2>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    
    <div class="form-group">
        <label>Title:</label>
        {{ form.title }}
    </div>
    
    <div class="form-group">
        <label>Description:</label>
        {{ form.description }}
    </div>
    
    <div class="form-group">
        <label>File:</label>
        {{ form.file }}
    </div>
    
    <button type="submit" class="btn btn-primary">Upload</button>
</form>

<!-- Display uploaded files -->
<h3>Uploaded Documents</h3>
{% for doc in documents %}
    <div class="document">
        <h4>{{ doc.title }}</h4>
        <p>{{ doc.description }}</p>
        <a href="{{ doc.file.url }}" download>Download</a>
        <small>Uploaded: {{ doc.uploaded_at }}</small>
    </div>
{% endfor %}

🔹 File Validation

Validate file size, type, and other properties to ensure security and prevent malicious uploads.

# validators.py
from django.core.exceptions import ValidationError

def validate_file_size(file):
    max_size_mb = 5
    if file.size > max_size_mb * 1024 * 1024:
        raise ValidationError(f'File size cannot exceed {max_size_mb}MB')

def validate_image_extension(file):
    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif']
    ext = file.name.lower().split('.')[-1]
    if f'.{ext}' not in valid_extensions:
        raise ValidationError('Only JPG, PNG, and GIF images are allowed')

# models.py
class Photo(models.Model):
    image = models.ImageField(
        upload_to='photos/',
        validators=[validate_file_size, validate_image_extension]
    )

Validation Errors:

❌ File size cannot exceed 5MB

❌ Only JPG, PNG, and GIF images are allowed

🔹 Image Processing Example

Automatically resize and optimize uploaded images using Pillow library to save storage space and improve performance.

# models.py
from django.db import models
from PIL import Image

class Photo(models.Model):
    title = models.CharField(max_length=200)
    image = models.ImageField(upload_to='photos/')
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        
        # Resize image
        img = Image.open(self.image.path)
        
        if img.height > 800 or img.width > 800:
            output_size = (800, 800)
            img.thumbnail(output_size)
            img.save(self.image.path)

🧠 Test Your Knowledge

What enctype is required for file upload forms?