Saturday, November 28, 2009

django ssl decorator

I recently found myself needing a way to require some django views be accessed only via a secure channel, as in ssl. A quick search led me to this post. I was able to quickly get up and running with this snippet and a couple of standard view functions, but ran into problems when trying to decorate a FormWizard view. The problem lied in the fact that FormWizards are implemented as classes with overridden __call__ methods. Long story short, I reworked the decorator as a class to work with functions and classes implementing __call__.

try:
  from functools import update_wrapper
except ImportError:
  from django.utils.functional import update_wrapper

class ssl_required(object):
  '''Decorator class to force ssl'''
  def __init__(self, func):
    self.func = func
    update_wrapper(self, func)

  def __get__(self, obj, cls=None):
    func = self.func.__get__(obj, cls)
    return ssl_required(func)

  def __call__(self, req, *args, **kwargs):
    if req.is_secure() or \
        not getattr(settings, 'HTTPS_SUPPORT', True):
      return self.func(req, *args, **kwargs)
    url = req.build_absolute_uri(req.get_full_path())
    url = url.replace('http://', 'https://')
    return HttpResponseRedirect(url)