In Django currently Postgres JSONField model field is shown as plain JSON text in CharField form field.
I'd like to present data in CharField as YAML text (while keeping it in JSON format internally) and while saving convert it back to JSON like:
yaml.dump(json.loads(value))
Current:
How to accomplish that?
Thanks.
Solution is to subclass JSONField (both model and form) and just replace json with yaml. Made as separate package: https://github.com/mike-tk/django-yamlfield
from django.contrib.postgres import fields, forms
import yaml
from django.utils.translation import gettext_lazy as _
class InvalidYAMLInput(str):
pass
class YAMLString(str):
pass
class YAMLFormField(forms.JSONField):
default_error_messages = {
'invalid': _("'%(value)s' value must be valid YAML."),
}
def to_python(self, value):
if self.disabled:
return value
if value in self.empty_values:
return None
elif isinstance(value, (list, dict, int, float, YAMLString)):
return value
try:
converted = yaml.load(value)
except yaml.YAMLError:
raise forms.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={'value': value},
)
if isinstance(converted, str):
return YAMLString(converted)
else:
return converted
def bound_data(self, data, initial):
if self.disabled:
return initial
try:
return yaml.load(data)
except yaml.YAMLError:
return InvalidYAMLInput(data)
def prepare_value(self, value):
if isinstance(value, InvalidYAMLInput):
return value
return yaml.dump(value, default_flow_style=False)
class YAMLField(fields.JSONField):
def formfield(self, **kwargs):
defaults = {'form_class': YAMLFormField}
defaults.update(kwargs)
return super().formfield(**defaults)