@register.tag<EOL>def qurl(parser, token):
bits = token.split_contents()<EOL>if len(bits) < <NUM_LIT:2>:<EOL><INDENT>raise TemplateSyntaxError(<EOL>'<STR_LIT>'.format(bits[<NUM_LIT:0>]))<EOL><DEDENT>if bits.count('<STR_LIT:|>') > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError(<EOL>'<STR_LIT>'.format(bits[<NUM_LIT:0>]))<EOL><DEDENT>if bits.count('<STR_LIT:|>'):<EOL><INDENT>url = _get_url_node(parser, bits[:bits.index('<STR_LIT:|>')])<EOL>bits = bits[bits.index('<STR_LIT:|>')+<NUM_LIT:1>:]<EOL><DEDENT>else:<EOL><INDENT>url = parser.compile_filter(bits[<NUM_LIT:1>])<EOL>bits = bits[<NUM_LIT:2>:]<EOL><DEDENT>asvar = None<EOL>if len(bits) >= <NUM_LIT:2> and bits[-<NUM_LIT:2>] == '<STR_LIT>':<EOL><INDENT>asvar = bits[-<NUM_LIT:1>]<EOL>bits = bits[:-<NUM_LIT:2>]<EOL><DEDENT>qs = []<EOL>if len(bits):<EOL><INDENT>kwarg_re = re.compile(r"<STR_LIT>")<EOL>for bit in bits:<EOL><INDENT>match = kwarg_re.match(bit)<EOL>if not match:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>")<EOL><DEDENT>name, op, value = match.groups()<EOL>qs.append((name, op, parser.compile_filter(value),))<EOL><DEDENT><DEDENT>return QURLNode(url, qs, asvar)<EOL>
Append, remove or replace query string parameters (preserve order)

    {% qurl url [param]* [as <var_name>] %}

    {% qurl 'reverse_name' [reverse_params] | [param]* [as <var_name>] %}

param:
        name=value: replace all values of name by one value
        name=None: remove all values of name
        name+=value: append a new value for name
        name-=value: remove the value of name with the value

Example::

    {% qurl '/search?page=1&color=blue&color=green'
             order='name' page=None color+='red' color-='green' %}
    Output: /search?color=blue&order=name&color=red

    {% qurl request.get_full_path order='name' %}