From 74bb013cc1edb0f2fcf24c750d4d942cae507765 Mon Sep 17 00:00:00 2001 From: Marcin Nowak Date: Mon, 18 Jul 2016 20:04:35 +0200 Subject: [PATCH] Fixed #26905 -- Allowed using MultiValueDict-like objects as form data. --- django/forms/widgets.py | 17 ++++++++++------- tests/forms_tests/tests/test_forms.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 224bd3de4d..13d22672bf 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -13,7 +13,6 @@ from django.conf import settings from django.forms.utils import flatatt, to_current_timezone from django.templatetags.static import static from django.utils import datetime_safe, formats, six -from django.utils.datastructures import MultiValueDict from django.utils.dates import MONTHS from django.utils.deprecation import ( RemovedInDjango20Warning, RenameMethodsBase, @@ -331,9 +330,11 @@ class MultipleHiddenInput(HiddenInput): return mark_safe('\n'.join(inputs)) def value_from_datadict(self, data, files, name): - if isinstance(data, MultiValueDict): - return data.getlist(name) - return data.get(name) + try: + getter = data.getlist + except AttributeError: + getter = data.get + return getter(name) class FileInput(Input): @@ -602,9 +603,11 @@ class SelectMultiple(Select): return mark_safe('\n'.join(output)) def value_from_datadict(self, data, files, name): - if isinstance(data, MultiValueDict): - return data.getlist(name) - return data.get(name) + try: + getter = data.getlist + except AttributeError: + getter = data.get + return getter(name) @html_safe diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index 2da04a4ef4..773b89a7bc 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -41,6 +41,11 @@ class PersonNew(Form): birthday = DateField() +class MultiValueDictLike(dict): + def getlist(self, key): + return [self[key]] + + class FormsTestCase(SimpleTestCase): # A Form is a collection of Fields. It knows how to validate a set of data and it # knows how to render itself in a couple of default ways (e.g., an HTML table). @@ -867,6 +872,12 @@ Java f = SongForm(data) self.assertEqual(f.errors, {}) + # SelectMultiple uses ducktyping so that MultiValueDictLike.getlist() + # is called. + f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'})) + self.assertEqual(f.errors, {}) + self.assertEqual(f.cleaned_data['composers'], ['J']) + def test_multiple_hidden(self): class SongForm(Form): name = CharField() @@ -904,6 +915,12 @@ Java self.assertEqual(f.cleaned_data['composers'], ['J', 'P']) self.assertEqual(f.cleaned_data['name'], 'Yesterday') + # MultipleHiddenInput uses ducktyping so that + # MultiValueDictLike.getlist() is called. + f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'})) + self.assertEqual(f.errors, {}) + self.assertEqual(f.cleaned_data['composers'], ['J']) + def test_escaping(self): # Validation errors are HTML-escaped when output as HTML. class EscapingForm(Form):