diff options
| author | Giannis Terzopoulos <terzo.giannis@gmail.com> | 2025-03-19 12:21:41 +0100 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2025-03-25 12:23:41 -0300 |
| commit | a39c28706aa7a8c3effd0980ae6d59ae67299d85 (patch) | |
| tree | e29eddc646811bd754842288678dd2013f51bb44 /django/template | |
| parent | 9608678704a5f89b4c946eea93e90a0f6eb8e3ef (diff) | |
Fixed #35529 -- Added support for positional arguments in querystring template tag.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'django/template')
| -rw-r--r-- | django/template/defaulttags.py | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index d26d54a826..a511f17310 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -4,12 +4,13 @@ import re import sys import warnings from collections import namedtuple -from collections.abc import Iterable +from collections.abc import Iterable, Mapping from datetime import datetime from itertools import cycle as itertools_cycle from itertools import groupby from django.conf import settings +from django.http import QueryDict from django.utils import timezone from django.utils.html import conditional_escape, escape, format_html from django.utils.lorem_ipsum import paragraphs, words @@ -1173,17 +1174,23 @@ def now(parser, token): @register.simple_tag(name="querystring", takes_context=True) -def querystring(context, query_dict=None, **kwargs): +def querystring(context, *args, **kwargs): """ - Build a query string using `query_dict` and `kwargs` arguments. + Build a query string using `args` and `kwargs` arguments. This tag constructs a new query string by adding, removing, or modifying - parameters, starting from the given `query_dict` (defaulting to - `request.GET`). Keyword arguments are processed sequentially, with later - arguments taking precedence. + parameters from the given positional and keyword arguments. Positional + arguments must be mappings (such as `QueryDict` or `dict`), and + `request.GET` is used as the starting point if `args` is empty. + + Keyword arguments are treated as an extra, final mapping. These mappings + are processed sequentially, with later arguments taking precedence. A query string prefixed with `?` is returned. + Raise TemplateSyntaxError if a positional argument is not a mapping or if + keys are not strings. + For example:: {# Set a parameter on top of `request.GET` #} @@ -1197,18 +1204,31 @@ def querystring(context, query_dict=None, **kwargs): {# Use a custom ``QueryDict`` #} {% querystring my_query_dict foo=3 %} + + {# Use multiple positional and keyword arguments #} + {% querystring my_query_dict my_dict foo=3 bar=None %} """ - if query_dict is None: - query_dict = context.request.GET - params = query_dict.copy() - for key, value in kwargs.items(): - if value is None: - if key in params: - del params[key] - elif isinstance(value, Iterable) and not isinstance(value, str): - params.setlist(key, value) - else: - params[key] = value + if not args: + args = [context.request.GET] + params = QueryDict(mutable=True) + for d in [*args, kwargs]: + if not isinstance(d, Mapping): + raise TemplateSyntaxError( + "querystring requires mappings for positional arguments (got " + "%r instead)." % d + ) + for key, value in d.items(): + if not isinstance(key, str): + raise TemplateSyntaxError( + "querystring requires strings for mapping keys (got %r " + "instead)." % key + ) + if value is None: + params.pop(key, None) + elif isinstance(value, Iterable) and not isinstance(value, str): + params.setlist(key, value) + else: + params[key] = value query_string = params.urlencode() if params else "" return f"?{query_string}" |
