0

I have written a custom Django Model Field to store dateutil.relativedelta's. The field looks like this:

class RelativeDeltaField(models.CharField):
    description = "Relative delta"

    __metaclass__ = models.SubfieldBase

    max_length = 200

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = self.max_length
        super(RelativeDeltaField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if isinstance(value, relativedelta):
            return value

        try:
            return eval(value)
        except SyntaxError, e:
            logging.error("Mangled data for a relativedelta field. Was the data truncated in MySQL column? Either manually fix, or change the next line to 'return None' and manually fix. value=%r message=%r" % (value, e))
            raise

    def get_db_prep_save(self, value, connection):

        return repr(value)

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_prep_value(value)

I am trying to serialise an object with this field to json with:

serializers.serialize('json', obj)

But I get an error:

…
  File "/home/rory/tix/virtualenv/lib/python2.6/site-packages/django/core/serializers/json.py", line 58, in default
    return super(DjangoJSONEncoder, self).default(o)
  File "/usr/lib/python2.6/dist-packages/simplejson/encoder.py", line 190, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: relativedelta(hours=+1) is not JSON serializable

From using the pdb, I can see that o in this case is the object itself, it hasn't been converted to anything, nor serialised.

How do I fix this so I can serialise my field?

The Django documentation says ( https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#converting-field-data-for-serialization ) to add a value_to_string, which I do have.

Amandasaurus
  • 58,203
  • 71
  • 188
  • 248
  • How exactly do you want it to be serialized though? What format would you use to represent `relativedelta(hours=+1)` as a string? – Daniel Roseman Jun 15 '12 at 12:06
  • I would like the JSON serialiser to be the same as what's in the database, which is the ``repr`` of the value, i.e. it should be the string ``"relativedelta(hours=+1)"`` – Amandasaurus Jun 15 '12 at 12:23

1 Answers1

1

The code in the doc is just a boilerplate, you need to implement value_to_string to return a string representing the relativedelta.

The RelativeDeltaField is based on models.CharField, thus the get_prep_value() looks like

def get_prep_value(self, value):
    return self.to_python(value)

It's OK for CharField because the intended value in Python of the field is already a string. However, your customized version of to_python() returns relativedelta instead of string.

okm
  • 23,575
  • 5
  • 83
  • 90