Fixed #26905 -- Allowed using MultiValueDict-like objects as form data.

This commit is contained in:
Marcin Nowak 2016-07-18 20:04:35 +02:00 committed by Tim Graham
parent 2b759c94c5
commit 74bb013cc1
2 changed files with 27 additions and 7 deletions

View File

@ -13,7 +13,6 @@ from django.conf import settings
from django.forms.utils import flatatt, to_current_timezone from django.forms.utils import flatatt, to_current_timezone
from django.templatetags.static import static from django.templatetags.static import static
from django.utils import datetime_safe, formats, six from django.utils import datetime_safe, formats, six
from django.utils.datastructures import MultiValueDict
from django.utils.dates import MONTHS from django.utils.dates import MONTHS
from django.utils.deprecation import ( from django.utils.deprecation import (
RemovedInDjango20Warning, RenameMethodsBase, RemovedInDjango20Warning, RenameMethodsBase,
@ -331,9 +330,11 @@ class MultipleHiddenInput(HiddenInput):
return mark_safe('\n'.join(inputs)) return mark_safe('\n'.join(inputs))
def value_from_datadict(self, data, files, name): def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict): try:
return data.getlist(name) getter = data.getlist
return data.get(name) except AttributeError:
getter = data.get
return getter(name)
class FileInput(Input): class FileInput(Input):
@ -602,9 +603,11 @@ class SelectMultiple(Select):
return mark_safe('\n'.join(output)) return mark_safe('\n'.join(output))
def value_from_datadict(self, data, files, name): def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict): try:
return data.getlist(name) getter = data.getlist
return data.get(name) except AttributeError:
getter = data.get
return getter(name)
@html_safe @html_safe

View File

@ -41,6 +41,11 @@ class PersonNew(Form):
birthday = DateField() birthday = DateField()
class MultiValueDictLike(dict):
def getlist(self, key):
return [self[key]]
class FormsTestCase(SimpleTestCase): class FormsTestCase(SimpleTestCase):
# A Form is a collection of Fields. It knows how to validate a set of data and it # 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). # knows how to render itself in a couple of default ways (e.g., an HTML table).
@ -867,6 +872,12 @@ Java</label></li>
f = SongForm(data) f = SongForm(data)
self.assertEqual(f.errors, {}) 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): def test_multiple_hidden(self):
class SongForm(Form): class SongForm(Form):
name = CharField() name = CharField()
@ -904,6 +915,12 @@ Java</label></li>
self.assertEqual(f.cleaned_data['composers'], ['J', 'P']) self.assertEqual(f.cleaned_data['composers'], ['J', 'P'])
self.assertEqual(f.cleaned_data['name'], 'Yesterday') 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): def test_escaping(self):
# Validation errors are HTML-escaped when output as HTML. # Validation errors are HTML-escaped when output as HTML.
class EscapingForm(Form): class EscapingForm(Form):