1

Is there a way to control json serialization in django? Simple code below will return serialized object in json:

co = Collection.objects.all()
c = serializers.serialize('json',co)

The json will look similar to this:

[
    {
        "pk": 1,
        "model": "picviewer.collection",
        "fields": {
            "urlName": "architecture",
            "name": "\u0413\u043e\u0440\u043e\u0434 \u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430",
            "sortOrder": 0
        }
    },
    {
        "pk": 2,
        "model": "picviewer.collection",
        "fields": {
            "urlName": "nature",
            "name": "\u041f\u0440\u0438\u0440\u043e\u0434\u0430",
            "sortOrder": 1
        }
    },
    {
        "pk": 3,
        "model": "picviewer.collection",
        "fields": {
            "urlName": "objects",
            "name": "\u041e\u0431\u044a\u0435\u043a\u0442\u044b \u0438 \u043d\u0430\u0442\u044e\u0440\u043c\u043e\u0440\u0442",
            "sortOrder": 2
        }
    }
]

You can see it's serializing it in a way that you are able to re-create the whole model, shall you want to do this at some point - fair enough, but not very handy for simple JS ajax in my case: I want bring the traffic to minimum and make the whole thing little clearer.

What I did is I created a view that passes the object to a .json template and the template will do something like this to generate "nicer" json output:

[
{% if collections %}
    {% for c in collections %}
{"id": {{c.id}},"sortOrder": {{c.sortOrder}},"name": "{{c.name}}","urlName": "{{c.urlName}}"}{% if not forloop.last %},{% endif %}
    {% endfor %}
{% endif %}
]

This does work and the output is much (?) nicer:

[
    {
        "id": 1,
        "sortOrder": 0,
        "name": "Город и архитектура",
        "urlName": "architecture"
    },
    {
        "id": 2,
        "sortOrder": 1,
        "name": "Природа",
        "urlName": "nature"
    },
    {
        "id": 3,
        "sortOrder": 2,
        "name": "Объекты и натюрморт",
        "urlName": "objects"
    } 
]

However, I'm bothered by the fast that my solution uses templates (an extra step in processing and possible performance impact) and it will take manual work to maintain shall I update the model, for example.

I'm thinking json generating should be part of the model (correct me if I'm wrong) and done with either native python-json and django implementation but can't figure how to make it strip the bits that I don't want.

One more thing - even when I restrict it to a set of fields to serialize, it will keep the id always outside the element container and instead present it as "pk" outside of it.

abolotnov
  • 4,282
  • 9
  • 56
  • 88

4 Answers4

2

I would suggest you use the json library to encode your data, instead of just constructing the json-like string yourself. The code above doesn't seem to handle escaping properly, for one thing. And there's not much to gain by writing your own serializer (except for bugs).

Assaf Lavie
  • 73,079
  • 34
  • 148
  • 203
2

That's really easy. Quick example:

from django.http import HttpResponse
from django.utils import simplejson

def simple_view(request):
    response = {'string': "test",
                'number': 42,
                'array': [1, 2, 3],
                'js_object': dict(foo="bar")}
    return HttpResponse(simplejson.dumps(response),
                        mimetype="application/json")

This view will return the equivalent of the following JSON:

{"string": "test",
 "number": 42,
 "array": [1, 2, 3],
 "js_object": {foo: "bar"}}

EDIT: And yes, Assaf Lavie is right, your template can spew invalid JSON.

alex vasi
  • 5,304
  • 28
  • 31
  • This works for arrays but I don't think django modes are serializable this way. – abolotnov Feb 27 '11 at 20:16
  • I think he's implying you should copy the fields from the model object you want into a JSON-serializable type like list or dict. `obj = Collection.objects.get(pk=1); simplejson.dumps(dict(urlName=obj.urlName, name=obj.name, sortOrder=obj.sortOder)`. But just like in [somebody else's answer](http://stackoverflow.com/questions/5129794/django-control-json-serialization/5130423#5130423), Piston can do this step for you :) – Bluu Feb 28 '11 at 00:12
  • This more or less works with some manual pre-processing - some of the model fields aren't serializable by simplejson and I have to convert them to strings :( – abolotnov Mar 02 '11 at 19:12
0
def view( request):
    m_all = list(model.objects.all().values())

    return HttpResponse(simplejson.dumps(m_all))

This should solve the problem. Using values() and converting to list should produce the result you wanted.

firatto
  • 19
  • 1
  • 9
0

Rather than writing anything yourself, let Piston do the work of serializing Django models to JSON. By default it just serializes the model's fields, no metadata. And you can easily list which fields--even related fields--to include or exclude. No extra templates, and very little view code.

Bluu
  • 5,226
  • 4
  • 29
  • 34
  • Piston doesn't seem be supported - last code committed 6 months ago, issues don't seem to be getting replied/resolved. – abolotnov Mar 02 '11 at 11:43
  • Fair. I've been using it in an internal company project doing exactly what you need with success, but there have been times I had to work around long-open bugs. As an alternative, if you want the new hotness, check out [Tastypie](https://github.com/toastdriven/django-tastypie). – Bluu Mar 02 '11 at 17:02
  • there is a community fork in progress with approval of jesper, the author of piston.that being said, you should just install on of the many forks that close some open bugs. for instance mine, http://bitbucket.org/wires/django-piston – wires Apr 26 '11 at 22:09