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'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.
# 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.
{# 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.
# 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.
# 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.