diff --git a/AUTHORS b/AUTHORS index 4277dde2af..6c3cd58b7c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -771,6 +771,7 @@ answer newbie questions, and generally made Django that much better: William Schwartz Will Hardy Wilson Miner + Wim Glenn wojtek Xia Kai Yann Fouillat diff --git a/django/http/request.py b/django/http/request.py index f3754ba2ff..84230be6e0 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -402,6 +402,19 @@ class QueryDict(MultiValueDict): value) self._mutable = mutable + @classmethod + def fromkeys(cls, iterable, value='', mutable=False, encoding=None): + """ + Return a new QueryDict with keys (may be repeated) from an iterable and + values from value. + """ + q = cls('', mutable=True, encoding=encoding) + for key in iterable: + q.appendlist(key, value) + if not mutable: + q._mutable = False + return q + @property def encoding(self): if self._encoding is None: diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 4dc801429e..e58e7b6d22 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -422,6 +422,16 @@ a subclass of dictionary. Exceptions are outlined here: Strings for setting both keys and values will be converted from ``encoding`` to unicode. If encoding is not set, it defaults to :setting:`DEFAULT_CHARSET`. +.. classmethod:: QueryDict.fromkeys(iterable, value='', mutable=False, encoding=None) + + .. versionadded:: 1.11 + + Creates a new ``QueryDict`` with keys from ``iterable`` and each value + equal to ``value``. For example:: + + >>> QueryDict.fromkeys(['a', 'a', 'b'], value='val') + + .. method:: QueryDict.__getitem__(key) Returns the value for the given key. If the key has more than one value, diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index e4677c6347..f3cc8820de 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -187,7 +187,7 @@ Models Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ -* ... +* Added :meth:`QueryDict.fromkeys() `. Serialization ~~~~~~~~~~~~~ diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py index 59ff3f4a70..2329a02531 100644 --- a/tests/httpwrappers/tests.py +++ b/tests/httpwrappers/tests.py @@ -25,7 +25,7 @@ from django.utils.encoding import force_str from django.utils.functional import lazystr -class QueryDictTests(unittest.TestCase): +class QueryDictTests(SimpleTestCase): def test_create_with_no_args(self): self.assertEqual(QueryDict(), QueryDict(str(''))) @@ -271,6 +271,44 @@ class QueryDictTests(unittest.TestCase): self.assertEqual(copy.copy(q).encoding, 'iso-8859-15') self.assertEqual(copy.deepcopy(q).encoding, 'iso-8859-15') + def test_querydict_fromkeys(self): + self.assertEqual(QueryDict.fromkeys(['key1', 'key2', 'key3']), QueryDict('key1&key2&key3')) + + def test_fromkeys_with_nonempty_value(self): + self.assertEqual( + QueryDict.fromkeys(['key1', 'key2', 'key3'], value='val'), + QueryDict('key1=val&key2=val&key3=val') + ) + + def test_fromkeys_is_immutable_by_default(self): + # Match behavior of __init__() which is also immutable by default. + q = QueryDict.fromkeys(['key1', 'key2', 'key3']) + with self.assertRaisesMessage(AttributeError, 'This QueryDict instance is immutable'): + q['key4'] = 'nope' + + def test_fromkeys_mutable_override(self): + q = QueryDict.fromkeys(['key1', 'key2', 'key3'], mutable=True) + q['key4'] = 'yep' + self.assertEqual(q, QueryDict('key1&key2&key3&key4=yep')) + + def test_duplicates_in_fromkeys_iterable(self): + self.assertEqual(QueryDict.fromkeys('xyzzy'), QueryDict('x&y&z&z&y')) + + def test_fromkeys_with_nondefault_encoding(self): + key_utf16 = b'\xff\xfe\x8e\x02\xdd\x01\x9e\x02' + value_utf16 = b'\xff\xfe\xdd\x01n\x00l\x00P\x02\x8c\x02' + q = QueryDict.fromkeys([key_utf16], value=value_utf16, encoding='utf-16') + expected = QueryDict('', mutable=True) + expected['ʎǝʞ'] = 'ǝnlɐʌ' + self.assertEqual(q, expected) + + def test_fromkeys_empty_iterable(self): + self.assertEqual(QueryDict.fromkeys([]), QueryDict('')) + + def test_fromkeys_noniterable(self): + with self.assertRaises(TypeError): + QueryDict.fromkeys(0) + class HttpResponseTests(unittest.TestCase):