from django.core.urlresolvers import reverse from django.template import FilterExpression from django.template import Library, Node, TemplateSyntaxError, resolve_variable from re import split from urllib import quote,unquote import re register = Library() class LinkNode(Node): def __init__(self, viewname, args, kwargs, add_to_current_link=False): self.viewname = viewname self.kwargs = kwargs self.args = args self.add_to_current_link = add_to_current_link def render(self,context): req = resolve_variable('request',context) args = [isinstance(k,FilterExpression) and k.resolve(context) or k for k in self.args] kwargs = req.GET.copy() for k,v in self.kwargs.items(): if isinstance(v, FilterExpression) and v.token: kwargs[k] = v.resolve(context) elif v: kwargs[k] = v try: url = not self.add_to_current_link and reverse(viewname=self.viewname, args=args, kwargs=None) or req.path except: url = req.path # check to see if named arguments have been passed query_started = url.find('?') > -1 query_string = "" raw_url = unquote(url) for k,values in kwargs.items(): if not isinstance(values,list): values = [values] params_added = "&".join( [quote(k) + "=" + quote(isinstance(v,str) and v or str(v)) for v in values if v and (not query_started or not re.search(r"\b" + re.escape(k + "=" + v) + r"\b", raw_url))]) if params_added: query_string += "&" + params_added if not query_started and len(query_string) > 0: query_string = "?" + query_string[1:] return url + query_string def link_persist(parser, token): """Url Tag that persists GET variables It has the same behaviour as the standard url tag found in django.template.defaulttags. But GET variables are passed by default to the 'reverse' url method that builds the final url. Specified parameters override GET parameters. Usage: {% link_persist viewname arg1, arg2, ... karg1=val1, karg2=val2 ... %} This has been tested with Django version 0.96""" bits = token.contents.split(' ', 2) if len(bits) < 2: raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0] args = [] kwargs = {} if len(bits) > 2: for arg in bits[2].split(','): if '=' in arg: k, v = arg.split('=', 1) kwargs[k] = parser.compile_filter(v) else: args.append(parser.compile_filter(arg)) return LinkNode(bits[1], args, kwargs) def link_add(parser, token): """Tag that adds parameters to the current url. Usage: {% link_add karg1=val1, karg2=val2 ... %} This has been tested with Django version 0.96""" bits = token.contents.split(' ', 2) args = [] kwargs = {} if len(bits) > 1: for arg in bits[1].split(','): if '=' in arg: k, v = arg.split('=', 1) kwargs[k] = parser.compile_filter(v) return LinkNode(None, args, kwargs, True) register.tag('link_persist', link_persist) register.tag('link_add', link_add)