Django get_object_or_404 replacement – get_object_or_template

Django’s built-in shortcut get_object_or_404 is a handy way to catch exceptions when a record isn’t found in the database (maybe the user messed with the URL params). But the generic 404 page isn’t always what you want to show. Sometimes it makes a bit more sense to show the user a separate template instead.

To solve this here’s a simple replacement function which makes use of a custom exception and some new middleware.

First the custom exception:

app/exceptions/custom.py

class NotFound(Exception):
def __init__(self, template):
# call the base class constructor
Exception.__init__(self, 'Record not found')
# set the template
self.template = template

view raw
custom.py
hosted with ❤ by GitHub

Next the middleware:

app/middleware/exceptions.py

from django.shortcuts import render
from app.exceptions.custom import NotFound
class ExceptionMiddleware(object):
def process_exception(self, request, exception):
if type(exception) == NotFound:
return render(request, exception.template)
return None

view raw
exceptions.py
hosted with ❤ by GitHub

Make sure you add the middleware to your settings:

MIDDLEWARE_CLASSES = (
'app.middleware.exceptions.ExceptionMiddleware',

view raw
settings.py
hosted with ❤ by GitHub

And finally the replacement function:

app/lib/shortcuts.py

from django.shortcuts import _get_queryset
from app.exceptions.custom import NotFound
def get_object_or_template(klass, template, *args, **kwargs):
# replacement for django.shortcuts.get_object_or_404()
# allows a template to be supplied instead of a 404
"""
Uses get() to return an object, or raises a Http404 exception if the object
does not exist.
klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the get() query.
Note: Like with get(), an MultipleObjectsReturned will be raised if more than one
object is found.
"""
queryset = _get_queryset(klass)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
raise NotFound(template)

view raw
shortcuts.py
hosted with ❤ by GitHub

You can now use this anywhere you were using get_object_or_404:

# get the product or show the not found template
product = get_object_or_template(Product, 'templates/product/not_found.html', pk=1)

view raw
view.py
hosted with ❤ by GitHub

Using this same design pattern you could easily create a get_object_or_redirect shortcut which redirects the user to another page instead of showing a template.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s