Django Static & Media Files: Your Digital Library & Photo Album ππΈ
The Big Picture: A Library Analogy
Imagine your Django website is like a library.
- Static files = The books, posters, and decorations that came WITH the library when it opened. They never change. The same poster stays on the wall forever.
- Media files = The photo album where visitors can ADD their own pictures. Users upload photos, documents, and files that grow over time.
This guide will teach you EVERYTHING about managing both!
ποΈ Part 1: Static Files Overview
What Are Static Files?
Static files are the permanent decorations of your website:
- CSS (how things look)
- JavaScript (how things move and interact)
- Images (logos, icons, backgrounds)
- Fonts (how text appears)
Simple Example:
# Your website's logo
# Located at: myapp/static/images/logo.png
# Your CSS styles
# Located at: myapp/static/css/style.css
# Your JavaScript
# Located at: myapp/static/js/app.js
Why βStaticβ?
Because these files donβt change based on who visits. Everyone sees the SAME logo, SAME stylesheet, SAME JavaScript.
Think of it like this:
- When you visit a store, the storeβs sign is STATIC - same for everyone
- But your shopping cart is DYNAMIC - different for each person
βοΈ Part 2: Static Files Settings
The Settings You Need
In your settings.py, youβll set up WHERE Django looks for static files:
# settings.py
# URL path to access static files in browser
STATIC_URL = '/static/'
# Where Django collects all static files
# for production deployment
STATIC_ROOT = BASE_DIR / 'staticfiles'
# Extra places to look for static files
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
What Each Setting Does
| Setting | Purpose | Example |
|---|---|---|
STATIC_URL |
URL prefix in browser | /static/ makes example.com/static/css/style.css |
STATIC_ROOT |
Folder for collected files | Used in production |
STATICFILES_DIRS |
Extra folders to search | Project-wide static files |
Real-World Analogy:
STATIC_URL= The section sign in the library (βFICTION ββ)STATIC_ROOT= The main shelf where ALL books goSTATICFILES_DIRS= Additional book carts around the library
π§Ή Part 3: The collectstatic Command
The Great Gathering
When youβre ready to deploy (go live), Django needs to gather ALL static files into ONE place.
python manage.py collectstatic
What Happens:
graph TD A["App 1 Static Files"] --> D["collectstatic"] B["App 2 Static Files"] --> D C["Project Static Files"] --> D D --> E["STATIC_ROOT Folder"] E --> F["Ready for Production!"]
Why Do This?
In development, Django finds files from multiple places. But in production, your web server (like Nginx) needs ONE folder.
Example Output:
$ python manage.py collectstatic
128 static files copied to '/home/mysite/staticfiles'.
Think of it like: Before a big party, you gather ALL the decorations from different rooms into ONE box. Much easier for the party planner to find everything!
π Part 4: Serving Static Files
Development vs Production
Development (DEBUG=True):
Django serves static files automatically through django.contrib.staticfiles.
# urls.py (development only)
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... your urls
]
if settings.DEBUG:
urlpatterns += static(
settings.STATIC_URL,
document_root=settings.STATIC_ROOT
)
Production (DEBUG=False): A dedicated web server handles static files:
# Nginx configuration example
location /static/ {
alias /home/mysite/staticfiles/;
}
Using Static Files in Templates
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet"
href="{% static 'css/style.css' %}">
</head>
<body>
<img src="{% static 'images/logo.png' %}"
alt="Logo">
<script src="{% static 'js/app.js' %}">
</script>
</body>
</html>
The {% static %} tag automatically creates the correct URL!
πΈ Part 5: Media Files Overview
What Are Media Files?
Media files are user-uploaded content:
- Profile pictures
- Document uploads
- Video submissions
- Any file a USER adds to your site
Key Difference:
| Static Files | Media Files |
|---|---|
| Created by developers | Created by users |
| Never change | Constantly growing |
| Part of code | NOT part of code |
| Safe to include in git | NEVER put in git |
Real-World Example:
- Instagram: The appβs logo = STATIC
- Instagram: Your vacation photos = MEDIA
βοΈ Part 6: Media Files Settings
The Settings You Need
# settings.py
# URL path to access media files
MEDIA_URL = '/media/'
# Folder where uploaded files are saved
MEDIA_ROOT = BASE_DIR / 'media'
Setting Up URLs
# urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... your urls
]
# Serve media files in development
if settings.DEBUG:
urlpatterns += static(
settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT
)
Folder Structure After Setup:
myproject/
βββ media/ β User uploads go here
β βββ avatars/
β β βββ user1.jpg
β βββ documents/
β βββ report.pdf
βββ static/ β Developer files
β βββ css/
β βββ js/
βββ manage.py
π€ Part 7: File Uploads
Creating an Upload Form
Step 1: The Model
# models.py
from django.db import models
class UserProfile(models.Model):
name = models.CharField(max_length=100)
avatar = models.ImageField(
upload_to='avatars/'
)
resume = models.FileField(
upload_to='resumes/'
)
Step 2: The Form
# forms.py
from django import forms
from .models import UserProfile
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['name', 'avatar', 'resume']
Step 3: The Template
<form method="POST"
enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
β οΈ CRITICAL: The enctype="multipart/form-data" is REQUIRED for file uploads!
The upload_to Parameter
# Static path
avatar = models.ImageField(upload_to='avatars/')
# Result: media/avatars/photo.jpg
# Dynamic path with function
def user_directory_path(instance, filename):
return f'user_{instance.user.id}/{filename}'
avatar = models.ImageField(
upload_to=user_directory_path
)
# Result: media/user_5/photo.jpg
π― Part 8: Handling Uploaded Files
In Your View
# views.py
from django.shortcuts import render, redirect
from .forms import ProfileForm
def upload_profile(request):
if request.method == 'POST':
form = ProfileForm(
request.POST,
request.FILES # Don't forget this!
)
if form.is_valid():
form.save()
return redirect('success')
else:
form = ProfileForm()
return render(request,
'upload.html',
{'form': form})
Accessing Uploaded Files
# In a view or template
profile = UserProfile.objects.get(id=1)
# Get the URL (for displaying)
image_url = profile.avatar.url
# Returns: /media/avatars/photo.jpg
# Get the file path (for processing)
file_path = profile.avatar.path
# Returns: /home/mysite/media/avatars/photo.jpg
# Get the filename
filename = profile.avatar.name
# Returns: avatars/photo.jpg
In Templates
{% if profile.avatar %}
<img src="{{ profile.avatar.url }}"
alt="Profile Picture">
{% endif %}
{% if profile.resume %}
<a href="{{ profile.resume.url }}">
Download Resume
</a>
{% endif %}
File Validation
# forms.py
from django.core.validators import (
FileExtensionValidator
)
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['file']
def clean_file(self):
file = self.cleaned_data['file']
# Check file size (5MB limit)
if file.size > 5 * 1024 * 1024:
raise forms.ValidationError(
"File too large! Max 5MB."
)
return file
π Quick Summary
graph TD A["Django Files"] --> B["Static Files"] A --> C["Media Files"] B --> D["CSS, JS, Images"] B --> E["Developer Created"] B --> F["collectstatic"] C --> G["User Uploads"] C --> H["Dynamic Content"] C --> I["FileField/ImageField"]
The Golden Rules
- Static = Developer stuff (CSS, JS, logos)
- Media = User stuff (uploads, avatars)
- Always use
{% static %}tag for static files - Always use
.urlattribute for media files - Never put media files in git!
- Always set
enctype="multipart/form-data"for upload forms
π You Did It!
You now understand:
- β What static and media files are
- β How to configure both in settings
- β
The magic of
collectstatic - β Serving files in dev and production
- β Creating file upload forms
- β Handling uploaded files in views
Your Django app is ready to handle files like a pro! π
