Getting Django to serialize objects without the "fields" field
Asked Answered
E

3

15

So I am working on writing the backend web service using Django to create & consume JSON, and my colleague is working on the ExtJS4 frontend. I'm using the wadofstuff serializer so I can serialize nested objects.

My colleague is having trouble parsing the json, specifically that Django puts the fields for an object inside a "fields" field. A short example:

The way things are being serialized now:

{
  "pk":1,
  "model":"events.phone",
  "fields":{
     "person":1,
     "name":"Cell",
     "number":"444-555-6666"
  }
}

The way I would like to serialize them to make ExtJS and my fellow developer happy:

{
  "pk":1,
  "model":"events.phone",
  "person":1,
  "name":"Cell",
  "number":"444-555-6666"
}

We will need to serialze some objects that are much more complicated than this however.

Is there any way short of writing my serializations by hand to make the Django or wadofstuff serializer not use a fields field?

Embarkation answered 22/2, 2012 at 21:14 Comment(2)
There are ways of changing this, but I'd be interested to know why your colleague is having such problems deserializing it - it's just one level down.Pyle
The problem is when we have a more complex object which has a four different models serialized within it, two of which has yet another model serialized within it.Embarkation
P
28

The best way to customize your serialization is to get Django to serialize to Python dicts first. Then you can post-process those dicts however you like, before dumping them out to JSON:

# this gives you a list of dicts
raw_data = serializers.serialize('python', Phone.objects.all())
# now extract the inner `fields` dicts
actual_data = [d['fields'] for d in raw_data]
# and now dump to JSON
output = json.dumps(actual_data)
Pyle answered 22/2, 2012 at 22:45 Comment(1)
This answer set me on the correct path. I had to add import json and update json.dumps to handle Date fields: json.dumps(data, cls=DjangoJSONEncoder). Oh, 12 years later...expected a cleaner solution from such a mature framework.Ovolo
J
28

Additionally, there's a more flexible way of modifying the general model JSON output in django. Take a look at the django.core.serializers module source code (which is quite simple - I'm a python newbie) and override the get_dump_object method:

from django.core.serializers.json import Serializer as Builtin_Serializer

class Serializer(Builtin_Serializer):
    def get_dump_object(self, obj):
        return self._current

In above example I get rid of both pk and model keys and I return the fields immediately.

The original code is:

def get_dump_object(self, obj):
    return {
        "pk": smart_text(obj._get_pk_val(), strings_only=True),
        "model": smart_text(obj._meta),
        "fields": self._current
    }

The solution to the original question could be, for example:

def get_dump_object(self, obj):
    metadata = {
        "pk": smart_text(obj._get_pk_val(), strings_only=True),
        "model": smart_text(obj._meta),
    }
    return dict(metadata.items() + self._current.items())
Ji answered 22/4, 2013 at 21:57 Comment(1)
With django 2.0 you get unsupported operand type(s) for +: 'dict_items' and 'odict_items'Theology
C
5

building on @ducin's answer:

1) extend Django's serializer:

from django.core.serializers.json import Serializer as DjangoSerializer

class Serializer(DjangoSerializer):  # name must be Serializer
    def get_dump_object(self, obj):
        self._current['id'] = smart_text(obj._get_pk_val(), strings_only=True)
        self._current['model'] = smart_text(obj._meta)
        return self._current

2) update the module that Django will use for type 'json':

from django.core.serializers import BUILTIN_SERIALIZERS

BUILTIN_SERIALIZERS['json'] = 'may_app.my_module'

assuming you put the Serializer above in may_app.my_module. you can put this code also in may_app.my_module, next to the Serializer.

3) from where you need to use the serializer:

from django.core import serializers
from my_app import my_module # to do the update

and then as normal:

pickle = serializers.serialize('json', MyModel.objects.all())
Cheltenham answered 12/10, 2018 at 21:4 Comment(1)
Instead of smart_text use from django.utils.encoding import smart_strPlebiscite

© 2022 - 2024 — McMap. All rights reserved.