Blog Implementation Guides 7 min read

Django Template Image Fallback for Media Fields

Handle empty ImageField and broken media URLs in Django templates using model properties, custom template tags, and fallback.pics placeholder URLs for missing files.

django placeholder imagedjango ImageFielddjango template fallbackplaceholder imagepython web
Django Template Image Fallback for Media Fields

Django's ImageField stores a relative path to a file. When the field is blank or the file has been deleted from media storage, the resulting URL either points to an empty string or to a path that returns a 404. Template logic that does not handle this case shows a broken image icon.

The fix combines Python model properties for server-side null resolution with HTML onerror attributes for files that exist in the database but are missing from storage.

ImageField behavior

How Django ImageField handles empty and missing files

An ImageField stores the file path relative to MEDIA_ROOT. If the field is blank, accessing field.url raises a ValueError. If the file was deleted from storage but the path remains in the database, the URL is valid but returns a 404.

Always check the field before accessing field.url in templates. The template tag {{ object.photo.url }} raises an exception if photo is blank.

The safest pattern is a model property that returns a fallback URL when the ImageField is empty or the file does not exist.

Model property

Add a get_photo_url model property

A model property that returns the ImageField URL or a fallback URL is the cleanest approach. The property centralizes the logic and makes it available in templates, views, serializers, and API responses.

Implementation tsx
# models.py
import urllib.parse
from django.db import models

class UserProfile(models.Model):
    name = models.CharField(max_length=200)
    avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)

    @property
    def avatar_url(self):
        if self.avatar:
            return self.avatar.url
        initials = ''.join(word[0] for word in self.name.split()[:2]).upper()
        return f'https://fallback.pics/api/v1/avatar/80?text={urllib.parse.quote(initials)}'

Template usage

Use the model property in Django templates

With the model property in place, the template simply references the property. No conditional logic is needed in the template itself.

Add an onerror attribute for the case where the file path exists in the database but the file is missing from storage — a common situation after S3 cleanup, manual file deletion, or CMS imports.

Implementation text
{# templates/users/profile.html #}
<img
  src="{{ user_profile.avatar_url }}"
  alt="{{ user_profile.name }}"
  width="80"
  height="80"
  onerror="this.onerror=null; this.src='https://fallback.pics/api/v1/avatar/80?text=??'"
/>

Template tag

Create a custom template tag for generic image fallback

For cases where you cannot add a property to the model — third-party models, or simple URL fields rather than ImageFields — a custom template tag generates the fallback URL.

Register it in a templatetags module and use it across templates that display external or optional image URLs.

Implementation tsx
# templatetags/image_fallback.py
from django import template
import urllib.parse

register = template.Library()

@register.simple_tag
def image_url(src, fallback_text='Image', width=400, height=400):
    if src:
        return src
    text = urllib.parse.quote(fallback_text)
    return f'https://fallback.pics/api/v1/{width}x{height}?text={text}'

{# In template #}
{% load image_fallback %}
<img
  src="{% image_url product.image_url product.name 400 400 %}"
  alt="{{ product.name }}"
  width="400"
  height="400"
/>

OG image

Resolve og:image in Django views

For blog posts and product detail pages, compute the og:image URL in the view function and pass it to the template context. This avoids putting fallback logic in the head template.

Implementation text
# views.py
def product_detail(request, slug):
    product = get_object_or_404(Product, slug=slug)
    og_image = (
        product.image.url if product.image
        else f'https://fallback.pics/api/v1/1200x630.jpg?text={urllib.parse.quote(product.name)}'
    )
    return render(request, 'products/detail.html', {
        'product': product,
        'og_image': og_image,
    })

Storage check

Check file existence for S3 and remote storage

If your media files are stored on S3 or another remote backend via django-storages, checking the ImageField's truthiness only tells you whether the path is stored — not whether the file actually exists.

For production apps with user-uploaded content, run a periodic management command to audit image fields and pre-populate a fallback_image_url field. This is cheaper than hitting S3 for an existence check on every page request.

Key takeaways

What to standardize before shipping

  • Never call field.url in a template without checking the field first — it raises ValueError when blank.
  • A model property that returns the field URL or a generated fallback is the cleanest server-side approach.
  • A custom template tag handles fallback for models you cannot modify or for simple URL string fields.
  • Add an onerror attribute for files that exist in the database but are missing from storage after cleanup.
  • Compute og:image in the view function and pass it to the template context rather than resolving it in a head partial.

Production fallback layer

Use fallback.pics anywhere an image URL is accepted.

Start with one deterministic URL and standardize fallback behavior across your design system.

Read the docs