Skip to content

Instantly share code, notes, and snippets.

@anhtran
Last active December 17, 2015 04:18
Show Gist options
  • Save anhtran/5548975 to your computer and use it in GitHub Desktop.
Save anhtran/5548975 to your computer and use it in GitHub Desktop.
In some cases, you don't want to use the middleware. These tags will be useful to navigate users to HTTPS or not. I modified them from Django source files.
from django.template import Library, TemplateSyntaxError
from django.template.defaulttags import kwarg_re
from django.template.base import Node
from django.utils.encoding import smart_str
from django.conf import settings
from django.contrib.sites.models import Site
register = Library()
"""
Example: {% secure_url "admin:index" %} or {% unsecure_url "homepage" as home %}
"""
class URLNode(Node):
def __init__(self, view_name, args, kwargs, asvar, legacy_view_name=True, secure=True):
self.view_name = view_name
self.legacy_view_name = legacy_view_name
self.args = args
self.kwargs = kwargs
self.asvar = asvar
self.secure = secure
def render(self, context):
from django.core.urlresolvers import reverse, NoReverseMatch
args = [arg.resolve(context) for arg in self.args]
kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context))
for k, v in self.kwargs.items()])
view_name = self.view_name
if not self.legacy_view_name:
view_name = view_name.resolve(context)
# Try to look up the URL twice: once given the view name, and again
# relative to what we guess is the "main" app. If they both fail,
# re-raise the NoReverseMatch unless we're using the
# {% url ... as var %} construct in which cause return nothing.
url = ''
try:
url = reverse(view_name, args=args, kwargs=kwargs, current_app=context.current_app)
except NoReverseMatch, e:
if settings.SETTINGS_MODULE:
project_name = settings.SETTINGS_MODULE.split('.')[0]
try:
url = reverse(project_name + '.' + view_name,
args=args, kwargs=kwargs,
current_app=context.current_app)
except NoReverseMatch:
if self.asvar is None:
# Re-raise the original exception, not the one with
# the path relative to the project. This makes a
# better error message.
raise e
else:
if self.asvar is None:
raise e
current_site = Site.objects.get_current()
if self.secure:
s = "https://%(site)s%(url)s" % {'url': url, 'site': current_site}
else:
s = "http://%(site)s%(url)s" % {'url': url, 'site': current_site}
if self.asvar:
context[self.asvar] = s
return ''
else:
return s
@register.tag
def secure_url(parser, token):
bits = token.split_contents()
if len(bits) < 2:
raise TemplateSyntaxError("'%s' takes at least one argument"
" (path to a view)" % bits[0])
viewname = parser.compile_filter(bits[1])
args = []
kwargs = {}
asvar = None
bits = bits[2:]
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
for bit in bits:
match = kwarg_re.match(bit)
if not match:
raise TemplateSyntaxError("Malformed arguments to url tag")
name, value = match.groups()
if name:
kwargs[name] = parser.compile_filter(value)
else:
args.append(parser.compile_filter(value))
if settings.DEBUG:
return URLNode(viewname, args, kwargs, asvar, legacy_view_name=False, secure=False)
return URLNode(viewname, args, kwargs, asvar, legacy_view_name=False, secure=True)
@register.tag
def unsecure_url(parser, token):
bits = token.split_contents()
if len(bits) < 2:
raise TemplateSyntaxError("'%s' takes at least one argument"
" (path to a view)" % bits[0])
viewname = parser.compile_filter(bits[1])
args = []
kwargs = {}
asvar = None
bits = bits[2:]
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
for bit in bits:
match = kwarg_re.match(bit)
if not match:
raise TemplateSyntaxError("Malformed arguments to url tag")
name, value = match.groups()
if name:
kwargs[name] = parser.compile_filter(value)
else:
args.append(parser.compile_filter(value))
return URLNode(viewname, args, kwargs, asvar, legacy_view_name=False, secure=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment