Most of our projects lately are now using JSON data storage in the database. This makes it very efficient for storing additional data without having to run alters are gigantic data sets. It also allows us to store different data for different kinds of sets within the same table.
Doing this in Django we originally created a JSONField. A simple custom field which would convert back and from from JSON to a Python object. Mostly this was going from a dictionary to a text-based form in the database (JSON). Recently in one project I took the time to update the field to fix a couple things as well as add support for it in the forms, and thus making it usable within the admin.
So, for the wanting, here’s our updated JSONField and the related form field.
from django.db import models from django import forms from django.utils import simplejson as json class JSONWidget(forms.Textarea): def render(self, name, value, attrs=None): if not isinstance(value, basestring): value = json.dumps(value, indent=2) return super(JSONWidget, self).render(name, value, attrs) class JSONFormField(forms.CharField): def __init__(self, *args, **kwargs): kwargs['widget'] = JSONWidget super(JSONFormField, self).__init__(*args, **kwargs) def clean(self, value): if not value: return try: return json.loads(value) except Exception, exc: raise forms.ValidationError(u'JSON decode error: %s' % (unicode(exc),)) class JSONField(models.TextField): __metaclass__ = models.SubfieldBase def formfield(self, **kwargs): return super(JSONField, self).formfield(form_class=JSONFormField, **kwargs) def to_python(self, value): if isinstance(value, basestring): value = json.loads(value) return value def get_db_prep_save(self, value): if value is None: return return json.dumps(value) def value_to_string(self, obj): value = self._get_val_from_obj(obj) return self.get_db_prep_value(value)
