mirror of
https://github.com/django/django.git
synced 2025-06-13 15:39:13 +00:00
Fixed #36446 -- Restored "q" in internal MediaType.params property.
The "q" key was removed while addressing ticket #36411. Despite `MediaType.params` is undocumented and considered internal, it was used in third-party projects (Zulip reported breakage), so this work restored the `q` key in `params`. Thanks Anders Kaseorg for the report. Regression in c075508b4de8edf9db553b409f8a8ed2f26ecead.
This commit is contained in:
parent
8fd21b0da3
commit
cf5f36bf90
@ -694,13 +694,13 @@ class QueryDict(MultiValueDict):
|
||||
|
||||
class MediaType:
|
||||
def __init__(self, media_type_raw_line):
|
||||
full_type, self._params = parse_header_parameters(
|
||||
full_type, self.params = parse_header_parameters(
|
||||
media_type_raw_line if media_type_raw_line else ""
|
||||
)
|
||||
self.main_type, _, self.sub_type = full_type.partition("/")
|
||||
|
||||
def __str__(self):
|
||||
params_str = "".join("; %s=%s" % (k, v) for k, v in self._params.items())
|
||||
params_str = "".join("; %s=%s" % (k, v) for k, v in self.params.items())
|
||||
return "%s%s%s" % (
|
||||
self.main_type,
|
||||
("/%s" % self.sub_type) if self.sub_type else "",
|
||||
@ -711,8 +711,8 @@ class MediaType:
|
||||
return "<%s: %s>" % (self.__class__.__qualname__, self)
|
||||
|
||||
@cached_property
|
||||
def params(self):
|
||||
params = self._params.copy()
|
||||
def range_params(self):
|
||||
params = self.params.copy()
|
||||
params.pop("q", None)
|
||||
return params
|
||||
|
||||
@ -735,20 +735,19 @@ class MediaType:
|
||||
if this_type != other_type and this_type != "*" and other_type != "*":
|
||||
return False
|
||||
|
||||
if bool(self.params) == bool(other.params):
|
||||
if bool(self.range_params) == bool(other.range_params):
|
||||
# If both have params or neither have params, they must be identical.
|
||||
result = self.params == other.params
|
||||
result = self.range_params == other.range_params
|
||||
else:
|
||||
# If self has params and other does not, it's a match.
|
||||
# If other has params and self does not, don't match.
|
||||
result = bool(self.params or not other.params)
|
||||
|
||||
result = bool(self.range_params or not other.range_params)
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
def quality(self):
|
||||
try:
|
||||
quality = float(self._params.get("q", 1))
|
||||
quality = float(self.params.get("q", 1))
|
||||
except ValueError:
|
||||
# Discard invalid values.
|
||||
return 1
|
||||
@ -768,7 +767,7 @@ class MediaType:
|
||||
return 0
|
||||
elif self.sub_type == "*":
|
||||
return 1
|
||||
elif not self.params:
|
||||
elif not self.range_params:
|
||||
return 2
|
||||
return 3
|
||||
|
||||
|
@ -17,3 +17,6 @@ Bugfixes
|
||||
* Fixed a regression in Django 5.2 that caused :meth:`.QuerySet.bulk_update` to
|
||||
incorrectly convert ``None`` to JSON ``null`` instead of SQL ``NULL`` for
|
||||
``JSONField`` (:ticket:`36419`).
|
||||
|
||||
* Fixed a regression in Django 5.2.2 where the ``q`` parameter was removed from
|
||||
the internal ``django.http.MediaType.params`` property (:ticket:`36446`).
|
||||
|
@ -15,6 +15,10 @@ class MediaTypeTests(TestCase):
|
||||
def test_str(self):
|
||||
self.assertEqual(str(MediaType("*/*; q=0.8")), "*/*; q=0.8")
|
||||
self.assertEqual(str(MediaType("application/xml")), "application/xml")
|
||||
self.assertEqual(
|
||||
str(MediaType("application/xml;type=madeup;q=42")),
|
||||
"application/xml; type=madeup; q=42",
|
||||
)
|
||||
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(MediaType("*/*; q=0.8")), "<MediaType: */*; q=0.8>")
|
||||
@ -34,6 +38,7 @@ class MediaTypeTests(TestCase):
|
||||
(" application/xml ", "application/xml"),
|
||||
("application/xml", " application/xml "),
|
||||
("text/vcard; version=4.0", "text/vcard; version=4.0"),
|
||||
("text/vcard; version=4.0; q=0.7", "text/vcard; version=4.0"),
|
||||
("text/vcard; version=4.0", "text/vcard"),
|
||||
]
|
||||
for accepted_type, mime_type in tests:
|
||||
@ -58,12 +63,64 @@ class MediaTypeTests(TestCase):
|
||||
# All main and sub types are defined, but there is no match.
|
||||
("application/xml", "application/html"),
|
||||
("text/vcard; version=4.0", "text/vcard; version=3.0"),
|
||||
("text/vcard; q=0.7", "text/vcard; version=3.0"),
|
||||
("text/vcard", "text/vcard; version=3.0"),
|
||||
]
|
||||
for accepted_type, mime_type in tests:
|
||||
with self.subTest(accepted_type, mime_type=mime_type):
|
||||
self.assertIs(MediaType(accepted_type).match(mime_type), False)
|
||||
|
||||
def test_params(self):
|
||||
tests = [
|
||||
("text/plain", {}, {}),
|
||||
("text/plain;q=0.7", {"q": "0.7"}, {}),
|
||||
("text/plain;q=1.5", {"q": "1.5"}, {}),
|
||||
("text/plain;q=xyz", {"q": "xyz"}, {}),
|
||||
("text/plain;q=0.1234", {"q": "0.1234"}, {}),
|
||||
("text/plain;version=2", {"version": "2"}, {"version": "2"}),
|
||||
(
|
||||
"text/plain;version=2;q=0.8",
|
||||
{"version": "2", "q": "0.8"},
|
||||
{"version": "2"},
|
||||
),
|
||||
(
|
||||
"text/plain;q=0.8;version=2",
|
||||
{"q": "0.8", "version": "2"},
|
||||
{"version": "2"},
|
||||
),
|
||||
(
|
||||
"text/plain; charset=UTF-8; q=0.3",
|
||||
{"charset": "UTF-8", "q": "0.3"},
|
||||
{"charset": "UTF-8"},
|
||||
),
|
||||
(
|
||||
"text/plain ; q = 0.5 ; version = 3.0",
|
||||
{"q": "0.5", "version": "3.0"},
|
||||
{"version": "3.0"},
|
||||
),
|
||||
("text/plain; format=flowed", {"format": "flowed"}, {"format": "flowed"}),
|
||||
(
|
||||
"text/plain; format=flowed; q=0.4",
|
||||
{"format": "flowed", "q": "0.4"},
|
||||
{"format": "flowed"},
|
||||
),
|
||||
("text/*;q=0.2", {"q": "0.2"}, {}),
|
||||
("*/json;q=0.9", {"q": "0.9"}, {}),
|
||||
("application/json;q=0.9999", {"q": "0.9999"}, {}),
|
||||
("text/html;q=0.0001", {"q": "0.0001"}, {}),
|
||||
("text/html;q=0", {"q": "0"}, {}),
|
||||
("text/html;q=0.", {"q": "0."}, {}),
|
||||
("text/html;q=.8", {"q": ".8"}, {}),
|
||||
("text/html;q= 0.9", {"q": "0.9"}, {}),
|
||||
('text/html ; q = "0.6"', {"q": "0.6"}, {}),
|
||||
]
|
||||
for accepted_type, params, range_params in tests:
|
||||
media_type = MediaType(accepted_type)
|
||||
with self.subTest(accepted_type, attr="params"):
|
||||
self.assertEqual(media_type.params, params)
|
||||
with self.subTest(accepted_type, attr="range_params"):
|
||||
self.assertEqual(media_type.range_params, range_params)
|
||||
|
||||
def test_quality(self):
|
||||
tests = [
|
||||
("*/*; q=0.8", 0.8),
|
||||
|
Loading…
x
Reference in New Issue
Block a user