Django Rest Framework and JSONField

45,333

Solution 1

If you're using Django Rest Framework >= 3.3, then the JSONField serializer is now included. This is now the correct way.

If you're using Django Rest Framework < 3.0, then see gzerone's answer.

If you're using DRF 3.0 - 3.2 AND you can't upgrade AND you don't need to serialize binary data, then follow these instructions.

First declare a field class:

from rest_framework import serializers

class JSONSerializerField(serializers.Field):
    """ Serializer for JSONField -- required to make field writable"""
    def to_internal_value(self, data):
        return data
    def to_representation(self, value):
        return value

And then add in the field into the model like

class MySerializer(serializers.ModelSerializer):
    json_data = JSONSerializerField()

And, if you do need to serialize binary data, you can always the copy official release code

Solution 2

In 2.4.x:

from rest_framework import serializers # get from https://gist.github.com/rouge8/5445149

class WritableJSONField(serializers.WritableField):
    def to_native(self, obj):
        return obj


class MyModelSerializer(serializers.HyperlinkedModelSerializer):
    my_json_field = WritableJSONField() # you need this.

Solution 3

serializers.WritableField is deprecated. This works:

from rest_framework import serializers
from website.models import Picture


class PictureSerializer(serializers.HyperlinkedModelSerializer):
    json = serializers.SerializerMethodField('clean_json')

    class Meta:
        model = Picture
        fields = ('id', 'json')

    def clean_json(self, obj):
        return obj.json

Solution 4

If and only if you know the first-level style of your JSON content (List or Dict), you can use DRF builtin DictField or ListField.

Ex:

class MyModelSerializer(serializers.HyperlinkedModelSerializer):
    my_json_field = serializers.DictField()

It works fine, with GET/PUT/PATCH/POST, including with nested contents.

Solution 5

Mark Chackerian script didn't work for me, I'd to force the json transform:

import json

class JSONSerializerField(serializers.Field):
    """ Serializer for JSONField -- required to make field writable"""

    def to_internal_value(self, data):
        json_data = {}
        try:
            json_data = json.loads(data)
        except ValueError, e:
            pass
        finally:
            return json_data
    def to_representation(self, value):
        return value

Works fine. Using DRF 3.15 and JSONFields in Django 1.8

Share:
45,333
Tzach
Author by

Tzach

Updated on February 07, 2020

Comments

  • Tzach
    Tzach about 4 years

    Given a Django model with a JSONField, what is the correct way of serializing and deserializing it using Django Rest Framework?

    I've already tried crating a custom serializers.WritableField and overriding to_native and from_native:

    from json_field.fields import JSONEncoder, JSONDecoder
    from rest_framework import serializers
    
    class JSONFieldSerializer(serializers.WritableField):
        def to_native(self, obj):
        return json.dumps(obj, cls = JSONEncoder)
    
        def from_native(self, data):
            return json.loads(data, cls = JSONDecoder)
    

    But when I try to updating the model using partial=True, all the floats in the JSONField objects become strings.

  • fixmycode
    fixmycode over 9 years
    I'd recommend not using JSONField as the classname because it would clash with the other class.
  • gzerone
    gzerone over 9 years
    fixmycode, thanks for your suggestion on the classname. Hmm..., that just a sample code, which copied from gist.github.com/rouge8/5445149, so you can change it whatever you want. But @Tzach, 'JSONFieldSerializer' is not a suitable name for the subclass of the 'serializers.WritableField' I think. It looks like that JSONFieldSerializer and MyModelSerializer are the same things. Hope to hear your opinion.
  • Tzach
    Tzach over 9 years
    Thanks @gzerone for your comment. I admit I didn't put too much attention for the new class name. Just wanted it not to cause clashes. Does JSONWritableField sounds better to you?
  • gzerone
    gzerone over 9 years
    Or WritableJSONField, ;)
  • David Dehghan
    David Dehghan over 9 years
    Yes. If you have an object that you want to serialize you just need to read it. This will not modify the original object that you are serializing.
  • mhsmith
    mhsmith about 9 years
    This is only valid for Django Rest Framework version 2. For version 3, see the answer by Mark Chackerian.
  • spacediver
    spacediver over 8 years
    And how you integrate this serializer field with model's JSONFields? Do you use ModelSerializer?
  • gzerone
    gzerone over 8 years
    Yea, since Django 1.8 & DRF 3.x, I replaced WritableJSONField with ListField or DictField in my case, which works fine with postgres array fields.
  • jonalvarezz
    jonalvarezz over 8 years
    I use serializers.Serializer, but with ModelSerializer should works too
  • Beau
    Beau over 8 years
    Noting that this does work with a ModelSerializer with DRF 3.2.
  • Scott Smith
    Scott Smith over 8 years
    None of the above worked for me, but this one did. Strange it is low on the list. On the client side I had to pass { "field": JSON.stringify(data), ... } with PATCH. Default jquery $.ajax calls broke out every value into long keys like "field[key1][key2][etc]": value.