Django url template with query parameters

12,533

Solution 1

There is no builtin support, but you can add one yourself. You can for example define the following template tag. We can for example construct files in boldface:

app/
    templatetags/
        __init__.py
        urlparams.py

Where in urlparams.py, we define:

from django import template
from urllib.parse import urlencode

register = template.Library()

@register.simple_tag
def urlparams(*_, **kwargs):
    safe_args = {k: v for k, v in kwargs.items() if v is not None}
    if safe_args:
        return '?{}'.format(urlencode(safe_args))
    return ''

In the template, we can then load the template tag and then use it like with:

{% load urlparams %}

<a href="{% url 'videos:index'}{% urlparams page='1' tag='sometag' %}">Next</a>

Note that strictly speaking, the URL parameters can contain the same key multiple times. This is here not possible. So we can not generate all possible URL parameters, but this is usually quite rare, and in my opinion not a good idea in the first place.

Solution 2

you can use default template filter and update your example

<a class="link-button" href="{% url 'videos:index' %}?tag={{ tag|default:'' }}&page={{ next|defaul:'' }}">Next</a>

output for empty tag and page is:

http://127.0.0.1:8000/videos/?tag=&page=

but if you want to dont print None Tag in url you must your own template tag or filter. simply you can write this template filter

@register.filter
def print_query_param(value, key)
   if value and key:
       return "%s=%s&" % (key, value)

and you can use it as below

<a class="link-button" href="{% url 'videos:index' %}?{{ tag|print_query_param:'tag' }}{{ next|print_query_param:'page' }}">Next</a>
Share:
12,533

Related videos on Youtube

Bjarte
Author by

Bjarte

Updated on June 04, 2022

Comments

  • Bjarte
    Bjarte almost 2 years

    I'm trying to pass query parameters via my view into a link, but it escapes me on how to actually achieve this in a good way.

    My template is as following:

    <a class="link-button" href="{% url 'videos:index' %}?tag={{ tag }}&page={{ next }}">Next</a>
    

    This returns what I want:

    http://127.0.0.1:8000/videos/?tag=1&page=2
    

    While this works, it's quite fragile, does not handle None values and there must be a better way of doing this.

    I tried to pass this via the urltemplate tag but it did not seem to be what I was looking for since it requires url config changes for path:

    {% url 'videos:index' page=next tag=tag %}
    

    Is there an actual way of doing this or a template tag I can use to get the parameters? I tried searching for this but it gave me a lot of old results and more path urls, like: /videos/page-1/tag-1/ which I'm not looking for.

    I was hoping to do something like:

    <a href="{% url 'videos:index'}?{% params page=next tag=tag %}">Next</a>
    
  • Bjarte
    Bjarte almost 6 years
    Thanks, had to use from urllib.parse import urlencode instead though. Python 3.x
  • Willem Van Onsem
    Willem Van Onsem almost 6 years
    @Bjarte: thanks for the feedback. That is now updated (since Python-2.x will no longer be supported within 1.5 years anyway)[
  • NSTJ
    NSTJ over 4 years
    note: it is important the directory is named exactly templatetags
  • Willem Van Onsem
    Willem Van Onsem about 4 years
    @Flimm: this only encodes one parameter. Furthermore, note that keys can contain characters that should be escaped as well. Hence it does not solve a problem.
  • Willem Van Onsem
    Willem Van Onsem about 4 years
    This does not urlencodes the parameter names, which can contain non-allowed characters as well.
  • Flimm
    Flimm about 4 years
    @WillemVanOnsem You do not need to pass urlencode when you are using literals for the param names, as in the original question. Furthermore, you can use urlencode for the param names if you are using a variable for the param name. See my answer.
  • Flimm
    Flimm about 4 years
    @WillemVanOnsem It is not needed in this case, since the literal tag and the literal page cannot contain non-allowed characters, since we know that the characters t, a, g, p, g and e are all allowed characters. See my edit.
  • tbrlpld
    tbrlpld almost 3 years
    👏 This should be a built in