Skip to main content

Command Palette

Search for a command to run...

Using Media Files in Django

Updated
3 min read

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 prefix

  • MEDIA_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