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

130๐Ÿ‘

โœ…

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 }}">
๐Ÿ‘คDrTyrsa

23๐Ÿ‘

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.

๐Ÿ‘คMichael

22๐Ÿ‘

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()
๐Ÿ‘คPrydie

7๐Ÿ‘

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()

๐Ÿ‘คCarl Marshall

7๐Ÿ‘

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

๐Ÿ‘คshad0w_wa1k3r

5๐Ÿ‘

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 ''
๐Ÿ‘คInti

0๐Ÿ‘

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()

Leave a comment