58

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?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Viktor Apoyan
  • 10,655
  • 22
  • 85
  • 147
  • Have you read this? https://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? – S.Lott Jun 23 '11 at 12:05
  • I want to get query part of current URL and add it to a link from that page. This must be done in template. – Viktor Apoyan Jun 23 '11 at 12:09
  • @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. – S.Lott Jun 23 '11 at 12:15
  • http://stackoverflow.com/questions/2882490/get-the-current-url-within-a-django-template – DrTyrsa Jun 23 '11 at 12:20
  • 7
    Why -1 ??? i think you should not give -1 ! – Viktor Apoyan Jun 23 '11 at 13:01

7 Answers7

129

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 }}">
boatcoder
  • 17,525
  • 18
  • 114
  • 178
DrTyrsa
  • 31,014
  • 7
  • 86
  • 86
  • 21
    For those just getting started, make sure you have the django.core.context_processors.request context processor enabled in your settings. – Andrew J Oct 12 '11 at 08:37
  • 2
    It's `django.template.context_processors.request` in later django versions, but anyway the above didn't work for me, returns empty string – stelios Jun 13 '18 at 21:32
  • @stelios I just faced the same problem and fixed it. You just need to pass `request` object to your template – phen0menon Sep 18 '19 at 18:59
  • I think the intention is to use the `urlencode` (pipe not dot) `` – Webucator May 11 '20 at 23:34
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.

chhantyal
  • 11,874
  • 7
  • 51
  • 77
Michael
  • 2,258
  • 1
  • 23
  • 31
  • 3
    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. – ceruleus Sep 28 '16 at 13:22
  • 1
    Note the `update()` in this case "... appends to the current dictionary items rather than replacing them.". See [QueryDict docs](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.QueryDict.update) – djvg Aug 20 '21 at 09:45
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()
jnns
  • 5,148
  • 4
  • 47
  • 74
Prydie
  • 1,807
  • 1
  • 20
  • 30
  • 4
    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: https://docs.djangoproject.com/en/1.10/ref/request-response/#django.http.QueryDict – Northern Nov 27 '16 at 16:16
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
  • 349
  • 4
  • 8
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
  • 12,955
  • 8
  • 67
  • 90
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
  • 3,443
  • 1
  • 29
  • 34
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()
Raymond Reddington
  • 1,709
  • 1
  • 13
  • 21