From 92d5b2f389314f12ad3f5c192e9c56a3938b2b32 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.2.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 | 12 ++++++++++++ 4 files changed, 23 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 8673727861..27644a3152 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 dea8ee0142..9979bcb8e2 100644 --- a/tests/template_tests/syntax_tests/test_querystring.py +++ b/tests/template_tests/syntax_tests/test_querystring.py @@ -20,6 +20,18 @@ class QueryStringTagTests(SimpleTestCase): "test_querystring_empty_get_params", context, expected="" ) + @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("/")) + for context, expected in [(non_empty_context, "?"), (empty_context, "")]: + with self.subTest(expected=expected): + self.assertRenderEqual( + "test_querystring_remove_all_params", + context, + expected, + ) + @setup({"test_querystring_non_empty_get_params": "{% querystring %}"}) def test_querystring_non_empty_get_params(self): request = self.request_factory.get("/", {"a": "b"})