mirror of
https://github.com/django/django.git
synced 2025-12-23 09:19:27 +00:00
Fixed #36783 -- Ensured proper handling of multi-value QueryDicts in querystring template tag.
Some checks are pending
Docs / spelling (push) Waiting to run
Docs / blacken-docs (push) Waiting to run
Docs / lint-docs (push) Waiting to run
Linters / flake8 (push) Waiting to run
Linters / isort (push) Waiting to run
Linters / black (push) Waiting to run
Linters / zizmor (push) Waiting to run
Tests / Windows, SQLite, Python 3.14 (push) Waiting to run
Tests / JavaScript tests (push) Waiting to run
Some checks are pending
Docs / spelling (push) Waiting to run
Docs / blacken-docs (push) Waiting to run
Docs / lint-docs (push) Waiting to run
Linters / flake8 (push) Waiting to run
Linters / isort (push) Waiting to run
Linters / black (push) Waiting to run
Linters / zizmor (push) Waiting to run
Tests / Windows, SQLite, Python 3.14 (push) Waiting to run
Tests / JavaScript tests (push) Waiting to run
Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com> Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
0071cb1efd
commit
922c4cf972
3 changed files with 65 additions and 3 deletions
|
|
@ -1296,6 +1296,10 @@ def querystring(context, *args, **kwargs):
|
|||
Keyword arguments are treated as an extra, final mapping. These mappings
|
||||
are processed sequentially, with later arguments taking precedence.
|
||||
|
||||
Passing `None` as a value removes the corresponding key from the result.
|
||||
For iterable values, `None` entries are ignored, but if all values are
|
||||
`None`, the key is removed.
|
||||
|
||||
A query string prefixed with `?` is returned.
|
||||
|
||||
Raise TemplateSyntaxError if a positional argument is not a mapping or if
|
||||
|
|
@ -1327,7 +1331,8 @@ def querystring(context, *args, **kwargs):
|
|||
"querystring requires mappings for positional arguments (got "
|
||||
"%r instead)." % d
|
||||
)
|
||||
for key, value in d.items():
|
||||
items = d.lists() if isinstance(d, QueryDict) else d.items()
|
||||
for key, value in items:
|
||||
if not isinstance(key, str):
|
||||
raise TemplateSyntaxError(
|
||||
"querystring requires strings for mapping keys (got %r "
|
||||
|
|
@ -1336,7 +1341,8 @@ def querystring(context, *args, **kwargs):
|
|||
if value is None:
|
||||
params.pop(key, None)
|
||||
elif isinstance(value, Iterable) and not isinstance(value, str):
|
||||
params.setlist(key, value)
|
||||
# Drop None values; if no values remain, the key is removed.
|
||||
params.setlist(key, [v for v in value if v is not None])
|
||||
else:
|
||||
params[key] = value
|
||||
query_string = params.urlencode() if params else ""
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ Django 6.0.1 fixes several bugs in 6.0.
|
|||
Bugfixes
|
||||
========
|
||||
|
||||
* ...
|
||||
* Fixed a regression in Django 6.0 where :ttag:`querystring` mishandled
|
||||
multi-value :class:`~django.http.QueryDict` keys, both by only preserving the
|
||||
last value and by incorrectly handling ``None`` values (:ticket:`36783`).
|
||||
|
|
|
|||
|
|
@ -58,6 +58,22 @@ class QueryStringTagTests(SimpleTestCase):
|
|||
context = RequestContext(request)
|
||||
self.assertRenderEqual("querystring_multiple", context, expected="?x=y&a=b")
|
||||
|
||||
@setup({"querystring_multiple_lists": "{% querystring %}"})
|
||||
def test_querystring_multiple_lists(self):
|
||||
request = self.request_factory.get("/", {"x": ["y", "z"], "a": ["b", "c"]})
|
||||
context = RequestContext(request)
|
||||
expected = "?x=y&x=z&a=b&a=c"
|
||||
self.assertRenderEqual("querystring_multiple_lists", context, expected=expected)
|
||||
|
||||
@setup({"querystring_lists_with_replacement": "{% querystring a=1 %}"})
|
||||
def test_querystring_lists_with_replacement(self):
|
||||
request = self.request_factory.get("/", {"x": ["y", "z"], "a": ["b", "c"]})
|
||||
context = RequestContext(request)
|
||||
expected = "?x=y&x=z&a=1"
|
||||
self.assertRenderEqual(
|
||||
"querystring_lists_with_replacement", context, expected=expected
|
||||
)
|
||||
|
||||
@setup({"querystring_empty_params": "{% querystring qd %}"})
|
||||
def test_querystring_empty_params(self):
|
||||
cases = [{}, QueryDict()]
|
||||
|
|
@ -111,6 +127,44 @@ class QueryStringTagTests(SimpleTestCase):
|
|||
context = RequestContext(request, {"my_dict": {"test": None}})
|
||||
self.assertRenderEqual("querystring_remove_dict", context, expected="?a=1")
|
||||
|
||||
@setup({"querystring_remove_querydict": "{% querystring request my_query_dict %}"})
|
||||
def test_querystring_remove_querydict(self):
|
||||
request = self.request_factory.get("/", {"x": "1"})
|
||||
my_qd = QueryDict(mutable=True)
|
||||
my_qd["x"] = None
|
||||
context = RequestContext(
|
||||
request, {"request": request.GET, "my_query_dict": my_qd}
|
||||
)
|
||||
self.assertRenderEqual("querystring_remove_querydict", context, expected="?")
|
||||
|
||||
@setup(
|
||||
{"querystring_remove_querydict_many": "{% querystring request my_query_dict %}"}
|
||||
)
|
||||
def test_querystring_remove_querydict_many(self):
|
||||
request = self.request_factory.get(
|
||||
"/", {"test": ["value1", "value2"], "a": [1, 2]}
|
||||
)
|
||||
|
||||
qd_none = QueryDict(mutable=True)
|
||||
qd_none["test"] = None
|
||||
|
||||
qd_list_none = QueryDict(mutable=True)
|
||||
qd_list_none.setlist("test", [None, None])
|
||||
|
||||
qd_empty_list = QueryDict(mutable=True)
|
||||
qd_empty_list.setlist("test", [])
|
||||
|
||||
for qd in (qd_none, qd_list_none, qd_empty_list):
|
||||
with self.subTest(my_query_dict=qd):
|
||||
context = RequestContext(
|
||||
request, {"request": request.GET, "my_query_dict": qd}
|
||||
)
|
||||
self.assertRenderEqual(
|
||||
"querystring_remove_querydict_many",
|
||||
context,
|
||||
expected="?a=1&a=2",
|
||||
)
|
||||
|
||||
@setup({"querystring_variable": "{% querystring a=a %}"})
|
||||
def test_querystring_variable(self):
|
||||
request = self.request_factory.get("/")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue