Static & Media Files#
Complete guide to handling static files and media uploads in Django.
📁 Static Files#
What are Static Files?#
Static files are files that don't change per request: - CSS files - JavaScript files - Images (logos, icons) - Fonts - Other assets
Development Setup#
1. Create Static Directories#
myproject/
├── myapp/
│ └── static/
│ └── myapp/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── main.js
│ └── images/
│ └── logo.png
└── static/ # Project-wide static files
└── css/
└── global.css
2. Settings Configuration#
# myproject/settings.py
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles' # For production
# Additional static file locations
STATICFILES_DIRS = [
BASE_DIR / 'static', # Project-wide static files
]
# Static files finders
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
3. Include Static Files in Templates#
<!-- Load static template tag -->
{% load static %}
<!-- CSS -->
<link rel="stylesheet" href="{% static 'myapp/css/style.css' %}">
<link rel="stylesheet" href="{% static 'css/global.css' %}">
<!-- JavaScript -->
<script src="{% static 'myapp/js/main.js' %}"></script>
<!-- Images -->
<img src="{% static 'myapp/images/logo.png' %}" alt="Logo">
4. URL Configuration (Development)#
# myproject/urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... your URL patterns
]
# Serve static files in development
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Production Setup#
Collect Static Files#
# Collect all static files to STATIC_ROOT
python manage.py collectstatic
# This copies all static files from:
# - STATICFILES_DIRS
# - Each app's static/ directory
# To: STATIC_ROOT
Serve with WhiteNoise (Recommended)#
# Install
pip install whitenoise
# myproject/settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # Add this
# ... other middleware
]
# WhiteNoise configuration
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Serve with Web Server (Alternative)#
# nginx.conf
server {
location /static/ {
alias /path/to/staticfiles/;
}
}
📸 Media Files#
What are Media Files?#
Media files are user-uploaded files: - User profile pictures - Document uploads - Images uploaded through forms - Any file uploaded by users
Development Setup#
1. Settings Configuration#
# myproject/settings.py
# Media files (user uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
2. URL Configuration (Development)#
# myproject/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)
3. Model Configuration#
# myapp/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='posts/') # Uploads to media/posts/
document = models.FileField(upload_to='documents/') # Uploads to media/documents/
# Date-based upload path
photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
# Uploads to: media/photos/2024/01/15/filename.jpg
4. Form Configuration#
# myapp/forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'image', 'document']
widgets = {
'image': forms.FileInput(attrs={'accept': 'image/*'}),
'document': forms.FileInput(attrs={'accept': '.pdf,.doc,.docx'}),
}
5. Template Configuration#
<!-- Display uploaded image -->
{% if post.image %}
<img src="{{ post.image.url }}" alt="{{ post.title }}">
{% endif %}
<!-- Display uploaded file -->
{% if post.document %}
<a href="{{ post.document.url }}">Download Document</a>
{% endif %}
<!-- Form with file upload -->
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
Important: Always use enctype="multipart/form-data" in forms with file uploads!
Production Setup#
Serve with Web Server#
# nginx.conf
server {
# Static files
location /static/ {
alias /path/to/staticfiles/;
}
# Media files
location /media/ {
alias /path/to/media/;
}
}
Or Use Cloud Storage (Recommended)#
# Install
pip install django-storages boto3 # For AWS S3
# Or
pip install django-storages # For other providers
# myproject/settings.py
# AWS S3 Configuration
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = 'us-east-1'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
🎯 File Upload Handling#
View with File Upload#
# myapp/views.py
from django.shortcuts import render, redirect
from .forms import PostForm
from .models import Post
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES) # Include request.FILES
if form.is_valid():
post = form.save()
return redirect('myapp:post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'myapp/post_form.html', {'form': form})
Manual File Handling#
# myapp/views.py
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
def upload_file(request):
if request.method == 'POST' and request.FILES:
uploaded_file = request.FILES['file']
# Save file
file_path = default_storage.save(
f'uploads/{uploaded_file.name}',
ContentFile(uploaded_file.read())
)
# Get file URL
file_url = default_storage.url(file_path)
return render(request, 'myapp/success.html', {'file_url': file_url})
return render(request, 'myapp/upload.html')
📋 File Field Options#
upload_to Options#
# Simple path
image = models.ImageField(upload_to='images/')
# Date-based path
image = models.ImageField(upload_to='images/%Y/%m/%d/')
# Callable function
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return f'user_{instance.user.id}/{filename}'
image = models.ImageField(upload_to=user_directory_path)
# Model method
class Post(models.Model):
def get_upload_path(self, filename):
return f'posts/{self.slug}/{filename}'
image = models.ImageField(upload_to=get_upload_path)
File Validation#
# myapp/models.py
from django.core.exceptions import ValidationError
def validate_image_size(value):
# Limit file size (5MB)
if value.size > 5 * 1024 * 1024:
raise ValidationError('Image size cannot exceed 5MB.')
def validate_image_extension(value):
# Allow only specific extensions
allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif']
if not any(value.name.lower().endswith(ext) for ext in allowed_extensions):
raise ValidationError('Invalid image format.')
class Post(models.Model):
image = models.ImageField(
upload_to='posts/',
validators=[validate_image_size, validate_image_extension]
)
🗑️ Delete Files#
Delete File When Model Deleted#
# myapp/models.py
from django.db.models.signals import pre_delete
from django.dispatch import receiver
@receiver(pre_delete, sender=Post)
def delete_post_files(sender, instance, **kwargs):
# Delete associated files
if instance.image:
instance.image.delete(save=False)
if instance.document:
instance.document.delete(save=False)
Manual File Deletion#
from django.core.files.storage import default_storage
# Delete file
default_storage.delete('path/to/file.jpg')
📁 Directory Structure#
myproject/
├── myapp/
│ └── static/
│ └── myapp/
│ ├── css/
│ ├── js/
│ └── images/
├── static/ # Project-wide static files
│ ├── css/
│ ├── js/
│ └── images/
├── staticfiles/ # Collected static files (production)
└── media/ # User uploads
├── posts/
├── documents/
└── photos/
⚙️ Settings Summary#
# myproject/settings.py
# Static Files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# Media Files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Static files finders (default)
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
✅ Best Practices#
- ✅ Use {% load static %} - Always load static tag in templates
- ✅ Organize by app - Keep static files in
app/static/app/ - ✅ Use collectstatic - Before deploying to production
- ✅ Use WhiteNoise - For serving static files in production
- ✅ Validate uploads - Check file size and type
- ✅ Use upload_to - Organize media files properly
- ✅ Delete old files - Clean up when models are deleted
- ✅ Use cloud storage - For production media files
✅ Next Steps#
- Learn Settings & Production for production configuration
- Learn Models for file field configuration
- Learn Forms for file upload forms
Pro Tip: Always use enctype="multipart/form-data" in forms with file uploads. Use request.FILES in views to access uploaded files. In production, serve media files with nginx or use cloud storage!