Fixed #27582 -- Allowed HStoreField to store null values.
This commit is contained in:
parent
9524fd9133
commit
bf84d042e0
|
@ -13,9 +13,9 @@ __all__ = ['HStoreField']
|
||||||
|
|
||||||
class HStoreField(Field):
|
class HStoreField(Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
description = _('Map of strings to strings')
|
description = _('Map of strings to strings/nulls')
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'not_a_string': _('The value of "%(key)s" is not a string.'),
|
'not_a_string': _('The value of "%(key)s" is not a string or null.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def db_type(self, connection):
|
def db_type(self, connection):
|
||||||
|
@ -30,7 +30,7 @@ class HStoreField(Field):
|
||||||
def validate(self, value, model_instance):
|
def validate(self, value, model_instance):
|
||||||
super(HStoreField, self).validate(value, model_instance)
|
super(HStoreField, self).validate(value, model_instance)
|
||||||
for key, val in value.items():
|
for key, val in value.items():
|
||||||
if not isinstance(val, six.string_types):
|
if not isinstance(val, six.string_types) and val is not None:
|
||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
self.error_messages['not_a_string'],
|
self.error_messages['not_a_string'],
|
||||||
code='not_a_string',
|
code='not_a_string',
|
||||||
|
|
|
@ -43,7 +43,9 @@ class HStoreField(forms.CharField):
|
||||||
|
|
||||||
# Cast everything to strings for ease.
|
# Cast everything to strings for ease.
|
||||||
for key, val in value.items():
|
for key, val in value.items():
|
||||||
value[key] = six.text_type(val)
|
if val is not None:
|
||||||
|
val = six.text_type(val)
|
||||||
|
value[key] = val
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def has_changed(self, initial, data):
|
def has_changed(self, initial, data):
|
||||||
|
|
|
@ -275,8 +275,9 @@ A more useful index is a ``GIN`` index, which you should create using a
|
||||||
|
|
||||||
.. class:: HStoreField(**options)
|
.. class:: HStoreField(**options)
|
||||||
|
|
||||||
A field for storing mappings of strings to strings. The Python data type
|
A field for storing key-value pairs. The Python data type used is a
|
||||||
used is a ``dict``.
|
``dict``. Keys must be strings, and values may be either strings or nulls
|
||||||
|
(``None`` in Python).
|
||||||
|
|
||||||
To use this field, you'll need to:
|
To use this field, you'll need to:
|
||||||
|
|
||||||
|
@ -287,6 +288,10 @@ A more useful index is a ``GIN`` index, which you should create using a
|
||||||
You'll see an error like ``can't adapt type 'dict'`` if you skip the first
|
You'll see an error like ``can't adapt type 'dict'`` if you skip the first
|
||||||
step, or ``type "hstore" does not exist`` if you skip the second.
|
step, or ``type "hstore" does not exist`` if you skip the second.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
|
Added the ability to store nulls. Previously, they were cast to strings.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
On occasions it may be useful to require or restrict the keys which are
|
On occasions it may be useful to require or restrict the keys which are
|
||||||
|
|
|
@ -144,8 +144,8 @@ Fields
|
||||||
.. class:: HStoreField
|
.. class:: HStoreField
|
||||||
|
|
||||||
A field which accepts JSON encoded data for an
|
A field which accepts JSON encoded data for an
|
||||||
:class:`~django.contrib.postgres.fields.HStoreField`. It will cast all the
|
:class:`~django.contrib.postgres.fields.HStoreField`. It casts all values
|
||||||
values to strings. It is represented by an HTML ``<textarea>``.
|
(except nulls) to strings. It is represented by an HTML ``<textarea>``.
|
||||||
|
|
||||||
.. admonition:: User friendly forms
|
.. admonition:: User friendly forms
|
||||||
|
|
||||||
|
@ -159,6 +159,10 @@ Fields
|
||||||
valid for a given field. This can be done using the
|
valid for a given field. This can be done using the
|
||||||
:class:`~django.contrib.postgres.validators.KeysValidator`.
|
:class:`~django.contrib.postgres.validators.KeysValidator`.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
|
Added the ability to store nulls.
|
||||||
|
|
||||||
``JSONField``
|
``JSONField``
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,10 @@ Minor features
|
||||||
* The new :class:`~django.contrib.postgres.aggregates.JSONBAgg` allows
|
* The new :class:`~django.contrib.postgres.aggregates.JSONBAgg` allows
|
||||||
aggregating values as a JSON array.
|
aggregating values as a JSON array.
|
||||||
|
|
||||||
|
* :class:`~django.contrib.postgres.fields.HStoreField` and
|
||||||
|
:class:`~django.contrib.postgres.forms.HStoreField` allow storing null
|
||||||
|
values.
|
||||||
|
|
||||||
:mod:`django.contrib.redirects`
|
:mod:`django.contrib.redirects`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,11 @@ class TestValidation(HStoreTestCase):
|
||||||
with self.assertRaises(exceptions.ValidationError) as cm:
|
with self.assertRaises(exceptions.ValidationError) as cm:
|
||||||
field.clean({'a': 1}, None)
|
field.clean({'a': 1}, None)
|
||||||
self.assertEqual(cm.exception.code, 'not_a_string')
|
self.assertEqual(cm.exception.code, 'not_a_string')
|
||||||
self.assertEqual(cm.exception.message % cm.exception.params, 'The value of "a" is not a string.')
|
self.assertEqual(cm.exception.message % cm.exception.params, 'The value of "a" is not a string or null.')
|
||||||
|
|
||||||
|
def test_none_allowed_as_value(self):
|
||||||
|
field = HStoreField()
|
||||||
|
self.assertEqual(field.clean({'a': None}, None), {'a': None})
|
||||||
|
|
||||||
|
|
||||||
class TestFormField(HStoreTestCase):
|
class TestFormField(HStoreTestCase):
|
||||||
|
@ -224,6 +228,11 @@ class TestFormField(HStoreTestCase):
|
||||||
value = field.clean('{"a": 1}')
|
value = field.clean('{"a": 1}')
|
||||||
self.assertEqual(value, {'a': '1'})
|
self.assertEqual(value, {'a': '1'})
|
||||||
|
|
||||||
|
def test_none_value(self):
|
||||||
|
field = forms.HStoreField()
|
||||||
|
value = field.clean('{"a": null}')
|
||||||
|
self.assertEqual(value, {'a': None})
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
field = forms.HStoreField(required=False)
|
field = forms.HStoreField(required=False)
|
||||||
value = field.clean('')
|
value = field.clean('')
|
||||||
|
|
Loading…
Reference in New Issue