23

I am trying to serialize a list of model object defined as:

class AnalysisInput(models.Model):
    input_user = models.CharField(max_length=45)
    input_title = models.CharField(max_length=45)
    input_date = models.DateTimeField()
    input_link = models.CharField(max_length=100)

I wrote a custom serializer (encoder) for json.dumps():

class AnalysisInputEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, AnalysisInput):
            return { "input_id" : obj.id,
                    "input_user" : obj.input_user,
                    "input_title" : obj.input_title,
                    "input_date" : obj.input_date.isoformat(),
                    "input_link" : obj.input_link }
        return json.JSONEncoder.default(self, obj)

When I serialize only one object, I am able to do it. When I try to serialize a list of object I get

[ objects..] is not JSON serializable

I searched but I didn't find where to work on.. I was thinking about writing a custom serializer also for list of model object.

3 Answers 3

50

A custom encoder is not called recursively. You are actually better off not using a custom encoder, and instead convert your objects to simple python types before serializing.

You could add a as_json or similarly named method to your model and calling that every time you need a JSON result:

class AnalysisInput(models.Model):
    input_user = models.CharField(max_length=45)
    input_title = models.CharField(max_length=45)
    input_date = models.DateTimeField()
    input_link = models.CharField(max_length=100)

    def as_json(self):
        return dict(
            input_id=self.id, input_user=self.input_user,
            input_title=self.input_title, 
            input_date=self.input_date.isoformat(),
            input_link=self.input_link)

Then in your view:

# one result
return HttpResponse(json.dumps(result.as_json()), content_type="application/json")

# a list of results
results = [ob.as_json() for ob in resultset]
return HttpResponse(json.dumps(results), content_type="application/json")
Sign up to request clarification or add additional context in comments.

7 Comments

It works, flawlessly :).. may I ask to you why I should not use custom encoders?
@Francesco: you'd have to write something that fully recurses over all lists, tuples and mappings to find your model objects. In your views, however, you know exactly where your model objects are located already, leading to easier to maintain code. You could combine the two techniques, of course; pyramid's JSON renderer supports __json__ methods on results for example.
When I try it, I get this exception > unbound method as_json() must be called with Category instance as first argument
@AlexJolig: you call it on actual instances of your model, not the model itself.
Looks great! Should the method name/signature be as_dict(self) instead since it's not really returning a json...
|
22

The best way I found to serialize your Django models is by using django.core.serializers to serialize your model list into JSON, XML, or YAML. No custom serialization code required! Documentation is here: https://docs.djangoproject.com/en/dev/topics/serialization/

Here is my implementation:

lead/models.py:

from django.db import models

class Lead(models.Model):
    name = models.CharField(max_length=50)
    email = models.CharField(max_length=256)
    phone = models.CharField(max_length=20)
    twitter_handle = models.CharField(max_length=20)
    github_handle = models.CharField(max_length=20)

lead/views.py:

from django.http import HttpResponse
from django.core import serializers
from lead.models import Lead

def index(request):
    leads_as_json = serializers.serialize('json', Lead.objects.all())
    return HttpResponse(leads_as_json, content_type='application/json')

The end result:

[{"pk": 1, "model": "lead.lead", "fields": {"twitter_handle": "johndoe", "name": "John Doe", "phone": "1(234)567-8910", "email": "[email protected]", "github_handle": "johndoe"}}]

1 Comment

how to customise the response ?
2

Simplest solution:

def index(request):
    data = serializers.serialize('json', Product.objects.all())
    return HttpResponse(data, content_type='application/json')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.