Не успел, я починить PickleField для Django, мне понадобилось создать JSONField. Задача оказалась решенной на раз/два, плюс ко всему добавился маленький и полезный виджет для JSONField'а, который показывает красиво отформатированный JSON в textarea. Сразу скажу, что contribute_to_class метод чуть менне, чем полностью, скопипастен с снипетта 377.
from django.conf import settings
from django.forms.widgets import Textarea
from django.db.models import SubfieldBase, TextField
from django.utils import simplejson
class JSONField(TextField):
__metaclass__ = SubfieldBase
def contribute_to_class(self, cls, name):
super(JSONField, self).contribute_to_class(cls, name)
def get_json(model):
return self.get_db_prep_value(getattr(model, self.attname))
setattr(cls, 'get_%s_json' % self.name, get_json)
def set_json(model, json):
setattr(model, self.attname, self.to_python(json))
setattr(cls, 'set_%s_json' % self.name, set_json)
def formfield(self, **kwargs):
kwargs['widget'] = JSONWidget(attrs={'class': 'vLargeTextField'})
return super(JSONField, self).formfield(**kwargs)
def get_db_prep_value(self, value):
return simplejson.dumps(value)
def to_python(self, value):
if not isinstance(value, basestring):
return value
try:
return simplejson.loads(value, encoding=settings.DEFAULT_CHARSET)
except ValueError, e:
# If string could not parse as JSON it's means that it's Python
# string saved to JSONField.
return value
class JSONWidget(Textarea):
"""
Prettify dumps of all non-string JSON data.
"""
def render(self, name, value, attrs=None):
if not isinstance(value, basestring) and value is not None:
value = simplejson.dumps(value, indent=4, sort_keys=True)
return super(JSONWidget, self).render(name, value, attrs)
Ну и пару примеров использования, напоследок:
>>> # Пусть у нас есть простая модель
>>> class Sample(models.Model):
... name = models.CharField(max_length=16)
... data = JSONField()
>>> # Создадим модель и сохраним в data поле настройки для ShadowBox
>>> sb = Sample.objects.create(name='ShadowBox',
... data={'autoDimensions': True,
... 'overlayOpacity': 0.5,
... 'skipSetup': True})
>>> # Теперь мы хотим напечатать эти настройки где-то в шаблоне
>>> sb.get_data_json()
'{"overlayOpacity": 0.5, "autoDimensions": true, "skipSetup": true}'
>>> # Вспомним, что нам вообщем-то не зачем кастомное значение для overlayOpacity
>>> del sb.data['overlayOpacity']
>>> sb.save()
>>> # И опять напечатаем настройки в шаблоне
>>> sb.get_data_json()
'{"autoDimensions": true, "skipSetup": true}'
зы. ShadowBox - это лучший лайтбокс для любого JavaScript фреймворка, имо.