How to add the current query string to an URL in a Django template?

Question:

When I load a page, there is a link “sameLink” that I want to append to it the query string of its containing page.

I have following URL:

somedomain/reporting/article-by-month?variable1=2008

How can I do that?

Asked By: Viktor Apoyan

||

Answers:

To capture the QUERY_PARAMS that were part of the request, you reference the dict that contains those parameters (request.GET) and urlencode them so they are acceptable as part of an href. request.GET.urlencode returns a string that looks like ds=&date_published__year=2008 which you can put into a link on the page like so:

<a href="sameLink/?{{ request.GET.urlencode }}">
Answered By: DrTyrsa

If you register a templatetag like follows:

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    updated.update(kwargs)
    return updated.urlencode()

you can modify the query string in your template:

<a href="{% url 'view_name' %}?{% query_transform request a=5 b=6 %}">

This will preserve anything already in the query string and just update the keys that you specify.

Answered By: Michael

I found that @Michael’s answer didn’t quite work when you wanted to update an existing query parameter.

The following worked for me:

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    for k, v in kwargs.items():
        updated[k] = v

    return updated.urlencode()
Answered By: Prydie

Following on from @Prydie (thank you!) I wanted to do the same, but in Python 3 & Django 1.10, with the addition of being able to strip querystring keys as well as modify them. To that end, I use this:

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    for k, v in kwargs.items():
        if v is not None:
            updated[k] = v
        else:
            updated.pop(k, 0)  # Remove or return 0 - aka, delete safely this key

    return updated.urlencode()

The python 3 bit being kwargs.items() over .iteritems()

Answered By: Carl Marshall

Informed by other answers but not needing the request passed in and only updates existing parameters.

@register.simple_tag(takes_context=True)
def querystring(context, **kwargs):
    """
    Creates a URL (containing only the querystring [including "?"]) derived
    from the current URL's querystring, by updating it with the provided
    keyword arguments.

    Example (imagine URL is ``/abc/?gender=male&name=Tim``)::

        {% querystring "name"="Diego" "age"=20 %}
        ?name=Diego&gender=male&age=20
    """
    request = context['request']
    updated = request.GET.copy()
    for k, v in kwargs.items():  # have to iterate over and not use .update as it's a QueryDict not a dict
        updated[k] = v

    return '?{}'.format(updated.urlencode()) if updated else ''
Answered By: Inti

Based on @Prydie’s solution (which itself uses @Michael’s), I constructed the tag to return the complete URL instead of just the parameter string.

My myproject/template_tags.py

from django import template


register = template.Library()


# https://stackoverflow.com/a/24658162/2689986
@register.simple_tag
def add_query_params(request, **kwargs):
    """
    Takes a request and generates URL with given kwargs as query parameters
    e.g.
    1. {% add_query_params request key=value %} with request.path=='/ask/'
        => '/ask/?key=value'
    2. {% add_query_params request page=2 %} with request.path=='/ask/?key=value'
        => '/ask/?key=value&page=2'
    3. {% add_query_params request page=5 %} with request.path=='/ask/?page=2'
        => '/ask/?page=5'
    """
    updated = request.GET.copy()
    for k, v in kwargs.items():
        updated[k] = v

    return request.build_absolute_uri('?'+updated.urlencode())

My settings.py

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            ...
            # loads custom template tags
            'libraries': {
                'mytags': 'config.template_tags',
            }
        },
    },
]

Sample usage in templates:

{% load mytags %}
<a href="{% add_query_params request page=2 %}">

Tested with Python3.6 in Django1.11.10

Answered By: shad0w_wa1k3r

Just a workaround if you don’t want loops or string concatenations.

String representation of url is something like '<WSGIRequest: GET 'our_url'>'
So if you want our_url, you just need to use regex for it.

our_url = re.search(r'/.*(?='>)', str(request)).group()
Answered By: Raymond Reddington
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.