From 65113401f1f6786f8a89dfcb7d0347924b317e7b Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:08:03 +0100 Subject: [PATCH] [5.1.x] Fixed #36182 -- Returned "?" if all parameters are removed in querystring template tag. Thank you to David Feeley for the report and Natalia Bidart for the review. Backport of 05002c153c5018e4429a326a6699c7c45e5ea957 from main. --- django/template/defaulttags.py | 14 +++++++------- docs/ref/templates/builtins.txt | 2 +- docs/releases/5.1.7.txt | 4 +++- .../syntax_tests/test_querystring.py | 9 +++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index ae74679ec6..1152452081 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -1194,18 +1194,18 @@ def querystring(context, query_dict=None, **kwargs): """ if query_dict is None: query_dict = context.request.GET - query_dict = query_dict.copy() + params = query_dict.copy() for key, value in kwargs.items(): if value is None: - if key in query_dict: - del query_dict[key] + if key in params: + del params[key] elif isinstance(value, Iterable) and not isinstance(value, str): - query_dict.setlist(key, value) + params.setlist(key, value) else: - query_dict[key] = value - if not query_dict: + params[key] = value + if not params and not query_dict: return "" - query_string = query_dict.urlencode() + query_string = params.urlencode() return f"?{query_string}" diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index c00baf3a07..7d2cf93085 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -965,7 +965,7 @@ This tag requires a :class:`~django.http.QueryDict` instance, which defaults to :attr:`request.GET ` if none is provided. If the :class:`~django.http.QueryDict` is empty and no additional parameters -are provided, an empty string is returned. A non-empty result includes a +are provided, an empty string is returned. Otherwise, the result includes a leading ``"?"``. .. admonition:: Using ``request.GET`` as default diff --git a/docs/releases/5.1.7.txt b/docs/releases/5.1.7.txt index 8143305a96..e184da6aca 100644 --- a/docs/releases/5.1.7.txt +++ b/docs/releases/5.1.7.txt @@ -9,4 +9,6 @@ Django 5.1.7 fixes several bugs in 5.1.6. Bugfixes ======== -* ... +* Fixed a bug in Django 5.1 where the ``{% querystring %}`` template tag + returned an empty string rather than ``"?"`` when all parameters had been + removed from the query string (:ticket:`36182`). diff --git a/tests/template_tests/syntax_tests/test_querystring.py b/tests/template_tests/syntax_tests/test_querystring.py index 3f1cf3d281..099be96f9e 100644 --- a/tests/template_tests/syntax_tests/test_querystring.py +++ b/tests/template_tests/syntax_tests/test_querystring.py @@ -17,6 +17,15 @@ class QueryStringTagTests(SimpleTestCase): output = template.render(context) self.assertEqual(output, "") + @setup({"test_querystring_remove_all_params": "{% querystring a=None %}"}) + def test_querystring_remove_all_params(self): + non_empty_context = RequestContext(self.request_factory.get("/?a=b")) + empty_context = RequestContext(self.request_factory.get("/")) + template = self.engine.get_template("test_querystring_remove_all_params") + for context, expected in [(non_empty_context, "?"), (empty_context, "")]: + with self.subTest(expected=expected): + self.assertEqual(template.render(context), expected) + @setup({"querystring_non_empty": "{% querystring %}"}) def test_querystring_non_empty(self): request = self.request_factory.get("/", {"a": "b"})