from django import template from django.http import QueryDict from django.utils.safestring import mark_safe from django.template.loader import get_template register = template.Library() class QueryStringNode(template.Node): def __init__(self, to_add, to_remove): self.to_add = to_add self.to_remove = to_remove def render(self, context): if 'request' not in context: raise template.TemplateSyntaxError( "'django.core.context_processors.request' not in TEMPLATE_CONTEXT_PROCESSORS" ) querydict = context['request'].GET.copy() return self.get_querystring(querydict, self.to_add, self.to_remove, context) def parse_to_remove(self, to_remove): if not to_remove: return [] return [r.strip() for r in to_remove.strip('"').split(',')] def parse_to_add(self, to_add): kw = {} to_add = to_add.strip('"') if to_add == '': return kw for a in to_add.split(','): k, v = a.strip().split('=') kw[k] = v return kw def get_querystring(self, querydict, to_add, to_remove, context): new_querydict = QueryDict(querydict.urlencode(), mutable=True) try: to_add = self.parse_to_add(to_add) to_remove = self.parse_to_remove(to_remove) except ValueError: raise template.TemplateSyntaxError("Unable to parse arguments") for r in to_remove: try: del new_querydict[r] except KeyError: pass for k, v in to_add.items(): if v.startswith('ctx:'): v = v.replace('ctx:', '') try: value = template.Variable(v).resolve(context) except template.VariableDoesNotExist: value = None if value: new_querydict[k] = value else: new_querydict[k] = v return new_querydict.urlencode() @register.tag def get_querystring(parser, token): """ First argument contains a list of variables that will be added to querystring. If value starts with "ctx:", the value will be taken from template context:: {% get_querystring "pk=ctx:object.pk,a=1" %} Second (optional) argument contains a list of variables that will be removed from the querystring:: {% get_querystring "pk=ctx:object.pk,a=1" "b,c" %} """ bits = token.split_contents() if len(bits) < 2: raise template.TemplateSyntaxError("%s takes at least one argument" % bits[0]) to_add = bits[1] try: to_remove = bits[2] except IndexError: to_remove = None return QueryStringNode(to_add, to_remove)