Easily update URL querystrings in a template
On devmarks.io I have a side bar with tags that, when clicked, filter the current list of bookmarks. I use querystrings for those filters so I needed a way to dynamically make links add a querystring to the current url.
The following example is how the template tag works in a template.
{% load url_tags %} <a href="{% add_query_string replace=True filter='filter-1' %}">Replaces the `filter` querystring with `filter=filter-1` on the current URLa> <a href="{% add_query_string filter='filter-2' %}">Adds a new `filter=filter-2` querystring on the current URLa> <a href="{% add_query_string view='view-0' %}">Adds a new `view=view-0` querystring on the current URLa>
And here is the Django template tag that provides the functionality above.
# templatetags/url_tags.py import urllib.parse as urlparse from urllib.parse import urlencode from django import template register = template.Library() @register.simple_tag(takes_context=True) def add_query_string(context, url: str = None, replace=False, **params) -> str: """ Mutates a querystring. Args: url: If no `url` is passed in, the current request context is used by default. replace: Replace all keys of the querystring if `True`. Defaults to `False`. """ if not url: request = context.get("request") url = request.get_full_path() # Tweaked from https://stackoverflow.com/a/2506477 url_parts = list(urlparse.urlparse(url)) query = None if replace: query = urlparse.parse_qsl(url_parts[4]) new_query = [] keys = set() for (k, v) in query: keys.add(k) if k in params: new_query.append((k, params[k])) else: new_query.append((k, v)) query = new_query # Handle params that aren't currently in the querystring for (k, v) in params.items(): if k not in keys: query.append((k, v)) else: query = urlparse.parse_qsl(url_parts[4]) for k, v in params.items(): query.append((k, v)) url_parts[4] = urlencode(query) return urlparse.urlunparse(url_parts)
This template tag provides a way to dynamically tweak a URL's querystring easily. Hopefully it works as well for you as it does for me.
Related Content
Hi, I'm Adam 👋
I've been a backend programmer for ~20 years in a variety of different languages before I discovered Python 10 years ago and never looked back.
alldjango
includes all the hard-won experience I've gained over the years building production-scale Django websites.
Feel free to reach out to me on Mastodon or make a GitHub Issue with questions, comments, or bitter invectives.
All code is licensed as MIT.