2014-03-15 01:34:49 +08:00
|
|
|
import json
|
|
|
|
|
|
|
|
from django import forms
|
|
|
|
from django.core.exceptions import ValidationError
|
2017-01-27 03:58:33 +08:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2014-03-15 01:34:49 +08:00
|
|
|
|
|
|
|
__all__ = ['HStoreField']
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreField(forms.CharField):
|
2016-05-29 20:17:07 +08:00
|
|
|
"""
|
|
|
|
A field for HStore data which accepts dictionary JSON input.
|
|
|
|
"""
|
2014-03-15 01:34:49 +08:00
|
|
|
widget = forms.Textarea
|
|
|
|
default_error_messages = {
|
|
|
|
'invalid_json': _('Could not load JSON data.'),
|
2016-05-29 20:17:07 +08:00
|
|
|
'invalid_format': _('Input must be a JSON dictionary.'),
|
2014-03-15 01:34:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
def prepare_value(self, value):
|
|
|
|
if isinstance(value, dict):
|
|
|
|
return json.dumps(value)
|
|
|
|
return value
|
|
|
|
|
|
|
|
def to_python(self, value):
|
|
|
|
if not value:
|
|
|
|
return {}
|
2015-08-08 01:06:56 +08:00
|
|
|
if not isinstance(value, dict):
|
|
|
|
try:
|
|
|
|
value = json.loads(value)
|
2017-06-21 03:16:37 +08:00
|
|
|
except json.JSONDecodeError:
|
2015-08-08 01:06:56 +08:00
|
|
|
raise ValidationError(
|
|
|
|
self.error_messages['invalid_json'],
|
|
|
|
code='invalid_json',
|
|
|
|
)
|
2016-05-29 20:17:07 +08:00
|
|
|
|
|
|
|
if not isinstance(value, dict):
|
|
|
|
raise ValidationError(
|
|
|
|
self.error_messages['invalid_format'],
|
|
|
|
code='invalid_format',
|
|
|
|
)
|
|
|
|
|
2014-03-15 01:34:49 +08:00
|
|
|
# Cast everything to strings for ease.
|
|
|
|
for key, val in value.items():
|
2016-12-09 08:17:02 +08:00
|
|
|
if val is not None:
|
2016-12-29 23:27:49 +08:00
|
|
|
val = str(val)
|
2016-12-09 08:17:02 +08:00
|
|
|
value[key] = val
|
2014-03-15 01:34:49 +08:00
|
|
|
return value
|
2015-05-24 22:56:48 +08:00
|
|
|
|
|
|
|
def has_changed(self, initial, data):
|
|
|
|
"""
|
|
|
|
Return True if data differs from initial.
|
|
|
|
"""
|
|
|
|
# For purposes of seeing whether something has changed, None is
|
|
|
|
# the same as an empty dict, if the data or initial value we get
|
|
|
|
# is None, replace it w/ {}.
|
|
|
|
initial_value = self.to_python(initial)
|
2017-01-21 21:13:44 +08:00
|
|
|
return super().has_changed(initial_value, data)
|