Skip to content

Instantly share code, notes, and snippets.

@eezis
Created December 7, 2013 17:48
Show Gist options
  • Save eezis/7846063 to your computer and use it in GitHub Desktop.
Save eezis/7846063 to your computer and use it in GitHub Desktop.
A Django Middleware Redirection class that provides a "last chance" to grab a developing 404 response and redirect it to a new URL.
"""
This piece of middleware grabs onto the tail end of process_response hook
and allows for redirects to be applied using regex matches.
Use Case: A legacy website with many old urls will have accumulated SEO mojo based
on external links. When the site is converted to a new fromat (say, drops the cruft like '.html')
or goes from abbreviated forms /art/id/t/234234 to /article/2014/january/technology/get-a-better-job
the old urls are at risk of breakage and could lose SEO mojo unless preserved
Best preservation comes from redirecting old content to new, which is easily accomplished
using 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'. This class catches
the stuff that falls through the cracks; it gives the developer a last chance effort to
catch and redirect. Say that "t" stood for technology in this url: /art/id/t/234234
it might be a good idea to redirect unmatched /art/id/t/foobard to /article/2014/technology
where the latter page lists an index of all articles by title
While you can perform a regex redirect in your http server, in urls.py, and in the django middleware,
that would miss the opportunity to preserve specific redirects that should live in the django Redirect table
nginx --> urls --> 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' -> LastChanceRedirect
*** NOTE WELL *** order is important this should be the last load in the middleware stack in settings.py
if you are using 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' it must come after that!
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
...
# put the redirectfallbackmiddleware end of list; order matters
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'<yourmoduledir>.redirectmiddleware.LastChanceRedirect',
)
https://docs.djangoproject.com/en/1.6/topics/http/middleware/
"""
from django import http
import re
redir_checks = {
# 'regexpattern_for_old_path' : 'new/path/redirect'
'^/test/([\w\.]{2,20})$': '/newurl',
}
class LastChanceRedirect(object):
# Defined as class-level attributes to be subclassing-friendly (from contrib.middlware.py)
response_gone_class = http.HttpResponseGone
response_redirect_class = http.HttpResponsePermanentRedirect
def process_response(self, request, response):
# only check 404 responses, all others should pass unmolested
if response.status_code != 404:
return response
sought_url = request.get_full_path()
matched = False
try:
for key, value in redir_checks.items():
if re.match(key,sought_url,re.I):
matched = True
new_path = value
except:
pass
if matched:
if new_path == '':
return self.response_gone_class()
else:
return self.response_redirect_class(new_path)
# Return the 'normal' response if a redirection was not found
return response
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment