Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use forms.TextArea for custom JSON field in Django admin site

I'm using a custom Django field to represent JSON encoded data:

class JSONField(models.TextField):
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, basestring):
                return json_decode(value)
        except ValueError:
            pass

        return value

    def get_prep_value(self, value):
        if value == "":
            return None
        if isinstance(value, dict) or isinstance(value, dict):
            value = json_encode(value)
            return super(JSONField, self).get_prep_value(value)

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value,connection=None)

The field itself works fine. However editting via the admin site is not possible since the string from the database is JSON-decoded and converted to a dictionary, so when the admin site is rendered, not the actual JSON string from the database is displayed (e.g. {"foo": "bar"}), but its dictionary representation (e.g. {u'foo': u'bar'}).

Obviously this leads to problems when saving the database object, because the dictionary's string representation is not a valid JSON string.

What I'd like to have is the admin site showing the actual database value (i.e. the string as it is saved in the database), instead of the string representation of the Python object returned by to_python.

My attempt would be to write a custom widget for this that just calls json_encode again on the dictionary - but is there a better way?

like image 375
ChrisM Avatar asked Dec 23 '11 02:12

ChrisM


1 Answers

value_from_object will help solve the problem. It's implementation depends on what serializer has been used, but for simplejson should looks like:

from django.utils import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder

class JSONField(models.TextField):
....

    def value_from_object(self, obj):
        return json.dumps(super(JSONField, self).value_from_object(obj))
like image 140
Alexey Savanovich Avatar answered Sep 30 '22 18:09

Alexey Savanovich