Using Media Files in Django
This is must-know Django stuff 👍Let’s walk through media files in Django clearly, from setup → usage → best practices.
1️⃣ What are media files?
Media files are user-uploaded files, like:
Profile photos
Blog featured images
PDFs, documents, etc.
👉 Different from static files (CSS, JS, images you ship with code).
2️⃣ Basic settings (very important)
In your project’s settings.py file.. add these ‘MEDIA_URL’ AND ‘MEDIA_ROOT’
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL→ URL prefixMEDIA_ROOT→ physical folder on disk
📁 Result:
project/
│
├── media/
│ └── blog/images/
├── static/
├── app/
└── manage.py
3️⃣ Model with media field
class BlogPost(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(
upload_to='blog/images/',
blank=True,
null=True
)
📌 Install Pillow (required for images):
pip install pillow
4️⃣ Show media in Django admin
Admin already handles media uploads automatically.
@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):
list_display = ('title', 'image')
5️⃣ Serve media during development (CRUCIAL)
urls.py (project level)
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# your urls here
]
if settings.DEBUG:
urlpatterns += static(
settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT
)
⚠️ Without this, images won’t show in templates.
6️⃣ Using media in templates
{% if post.image %}
<img src="{{ post.image.url }}" alt="{{ post.title }}">
{% endif %}
🧠 .url gives the public URL
🧠 .path gives the filesystem path
7️⃣ Upload via forms
forms.py
from django import forms
from .models import BlogPost
class BlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title', 'image']
template.html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
🚨 enctype="multipart/form-data" is mandatory
8️⃣ Handle media in views
def create_post(request):
if request.method == 'POST':
form = BlogPostForm(request.POST, request.FILES)
if form.is_valid():
form.save()
else:
form = BlogPostForm()
9️⃣ Deleting media files (important!)
Django does NOT delete files automatically when a model is deleted.
Auto-delete using signals
from django.db.models.signals import post_delete
from django.dispatch import receiver
@receiver(post_delete, sender=BlogPost)
def delete_image(sender, instance, **kwargs):
if instance.image:
instance.image.delete(False)
🔟 File size & type validation
def validate_image_size(file):
max_size = 2 * 1024 * 1024 # 2MB
if file.size > max_size:
raise ValidationError("Max file size is 2MB")
class BlogPost(models.Model):
image = models.ImageField(
upload_to='blog/images/',
validators=[validate_image_size]
)
11️⃣ Production setup (IMPORTANT)
🚫 Never serve media using Django in production
Use:
Nginx
S3 / Cloudflare R2
DigitalOcean Spaces
Example (Nginx):
location /media/ {
alias /path/to/media/;
}
12️⃣ Best practices (real-world)
✔ Separate static/ and media/
✔ Validate file size & type
✔ Use unique filenames (UUID)
✔ Delete unused files
✔ Use cloud storage for scalability

