# 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`](http://settings.py) file.. add these ‘MEDIA\_URL’ AND ‘MEDIA\_ROOT’

```python
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:

```plaintext
project/
│
├── media/
│   └── blog/images/
├── static/
├── app/
└── manage.py
```

---

## 3️⃣ Model with media field

```python
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):

```bash
pip install pillow
```

---

## 4️⃣ Show media in Django admin

Admin already handles media uploads automatically.

```python
@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'image')
```

---

## 5️⃣ Serve media during development (CRUCIAL)

### [`urls.py`](http://urls.py) (project level)

```python
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

```html
{% 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`](http://forms.py)

```python
from django import forms
from .models import BlogPost

class BlogPostForm(forms.ModelForm):
    class Meta:
        model = BlogPost
        fields = ['title', 'image']
```

### `template.html`

```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

```python
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

```python
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

```python
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):

```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

---
