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

7

59

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?

Freidafreight answered 23/6, 2011 at 12:1 Comment(5)
Have you read this? docs.djangoproject.com/en/1.3/topics/http/urls/#example It seems very clear how you capture parts of a URL. What's your question?Semiautomatic
I want to get query part of current URL and add it to a link from that page. This must be done in template.Freidafreight
@Nerses: Please update the question to explain completely what you are trying to do. Include code samples if possible, even if they don't work.Semiautomatic
#2882990Prothalamium
Why -1 ??? i think you should not give -1 !Freidafreight
P
132

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 }}">
Prothalamium answered 23/6, 2011 at 12:32 Comment(4)
For those just getting started, make sure you have the django.core.context_processors.request context processor enabled in your settings.Sigler
It's django.template.context_processors.request in later django versions, but anyway the above didn't work for me, returns empty stringJulio
@Julio I just faced the same problem and fixed it. You just need to pass request object to your templateMenis
I think the intention is to use the urlencode (pipe not dot) <a href="sameLink/?{{ request.GET.variable1|urlencode }}">Extension
I
24

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.

Iolanthe answered 10/6, 2014 at 7:43 Comment(2)
This and @Prydie's answer deserve more attention. I have an use case with filtering, sorting and pagination and without this idea I would be screwed. I see that use case as very common indeed.Mild
Note the update() in this case "... appends to the current dictionary items rather than replacing them.". See QueryDict docsChurning
U
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()
Unitary answered 9/7, 2014 at 15:45 Comment(1)
Here is the reason why update() function didn't quite work: "Just like the standard dictionary update() method, except it appends to the current dictionary items rather than replacing them." Refer to documentation here: docs.djangoproject.com/en/1.10/ref/request-response/…Felonry
W
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()

Weintraub answered 28/3, 2017 at 16:53 Comment(0)
S
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://mcmap.net/q/327016/-how-to-add-the-current-query-string-to-an-url-in-a-django-template
@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

Santiago answered 20/3, 2018 at 13:26 Comment(0)
A
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 ''
Arsis answered 28/10, 2017 at 11:16 Comment(0)
P
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()
Phage answered 30/10, 2019 at 11:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.