diff --git a/AUTHORS b/AUTHORS index 6c7a670737..71ebcdd3b2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -108,6 +108,7 @@ answer newbie questions, and generally made Django that much better: Bojan Mihelac Bouke Haarsma Božidar Benko + Brad Melin Brant Harris Brendan Hayward Brenton Simpson diff --git a/django/contrib/postgres/forms/hstore.py b/django/contrib/postgres/forms/hstore.py index bf562c0e8f..4ed99d1fda 100644 --- a/django/contrib/postgres/forms/hstore.py +++ b/django/contrib/postgres/forms/hstore.py @@ -9,10 +9,13 @@ __all__ = ['HStoreField'] class HStoreField(forms.CharField): - """A field for HStore data which accepts JSON input.""" + """ + A field for HStore data which accepts dictionary JSON input. + """ widget = forms.Textarea default_error_messages = { 'invalid_json': _('Could not load JSON data.'), + 'invalid_format': _('Input must be a JSON dictionary.'), } def prepare_value(self, value): @@ -31,6 +34,13 @@ class HStoreField(forms.CharField): self.error_messages['invalid_json'], code='invalid_json', ) + + if not isinstance(value, dict): + raise ValidationError( + self.error_messages['invalid_format'], + code='invalid_format', + ) + # Cast everything to strings for ease. for key, val in value.items(): value[key] = six.text_type(val) diff --git a/docs/releases/1.9.7.txt b/docs/releases/1.9.7.txt index 2f5555721f..d54fa96fdc 100644 --- a/docs/releases/1.9.7.txt +++ b/docs/releases/1.9.7.txt @@ -20,3 +20,6 @@ Bugfixes * Fixed ``on_commit`` callbacks execution order when callbacks make transactions (:ticket:`26627`). + +* Fixed ``HStoreField`` to raise a ``ValidationError`` instead of crashing on + non-dictionary JSON input (:ticket:`26672`). diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py index 8ebd757098..b927d8e19f 100644 --- a/tests/postgres_tests/test_hstore.py +++ b/tests/postgres_tests/test_hstore.py @@ -208,6 +208,13 @@ class TestFormField(PostgreSQLTestCase): self.assertEqual(cm.exception.messages[0], 'Could not load JSON data.') self.assertEqual(cm.exception.code, 'invalid_json') + def test_non_dict_json(self): + field = forms.HStoreField() + msg = 'Input must be a JSON dictionary.' + with self.assertRaisesMessage(exceptions.ValidationError, msg) as cm: + field.clean('["a", "b", 1]') + self.assertEqual(cm.exception.code, 'invalid_format') + def test_not_string_values(self): field = forms.HStoreField() value = field.clean('{"a": 1}')