Charles Williams
Charles Williams

Reputation: 573

Django "is not JSON serializable" - ajax, views.py - How to implement?

I have read the documentation, but I am not exactly sure how to implement serializer.serialize for JSON objects in my view.py. If anyone can help me understand this a little better. I have the following code in my view.py:

@user_passes_test(lambda u: u.is_superuser)
def ProjDetails(request):
    proj_id = request.GET['proj_id']
    proj = Proj.objects.filter(id=proj_id)
    role_list = ProjRole.objects.filter(proj=proj)
    proj = {
        "proj": proj,
        "roles": []
    }
    for r in role_list:
         proj['roles'].append(r.id)

    return HttpResponse(json.dumps(proj), content_type='application/json; charset=UTF-8')

I am trying to call this with .ajax (I am still working on the ajax, so it probably is not right):

$('#proj_list #sel_proj').click(function(){
   $('div.sel').removeClass("sel");
   $(this).addClass("sel");

   var project_id = $(this).data('id');

   $.ajax({
       url:'../../proj_details',
       data: {proj_id: proj_id},
       // dataType: 'html',
       success: function(data){
           $('#proj_display').html(data)
       },
       error: function () {
           alert("Failed to find the project!")
       }
});

Once I get the JSON call to work, then I will focus more on the ajax.

Biggest problem, I am getting a 500 http error with:

TypeError at ../proj_details
[<Project: Example>] is not JSON serializable

I am using Django 1.7, but I even added SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' to my settings.py without any luck. So I imported serializers from the django.core and tried to use serializer.serialize, but I am not understanding how to implement it I guess because my errors just keep getting worse. I have seen other posts with the same error, but still not understanding for my particular requirements.

+++++++++++++++ EDIT +++++++++++++++++++

So the only way I have been able to get this to work without multiple errors, circular errors, multiple argument errors, etc, is the following:

def ProjDetails(request):
    def date_handler(obj):
        return obj.strftime("%B %d, %Y") if hasattr(obj, 'strftime') else obj

        proj_id = request.GET['proj_id']
        proj = Proj.objects.get(id=proj_id)
        corp = Corp.objects.get(id=proj.corp.id)
        role_list = ProjRole.objects.filter(proj=proj).all()
        proj = {
        "proj": {
             'title': proj.title,
             'id': proj.id,
             'date': proj.date,
             'description': proj.description
        }
        "roles": [],
        "company": {
             'name': corp.name,
             'pic': unicode(corp.pic),
        }
    }
    for r in role_list:
         proj['roles'].append(r.name)

return HttpResponse(json.dumps(proj, default=date_handler), content_type='application/json; charset=UTF-8')

The only thing I don't like about this is I actually have to manually pull what attributes I want from the model into the dictionary, instead of all the attributes being pulled from the model and then I can choose which ones I want to use in my templates. I would rather not have to pull everything like my example above. The 'roles' = [] is giving me some hiccups too because I can't seem to get it to work when there are multiple roles for a proj object.

I like Eugene's method because it would be cleaner, but I can't seem to get it to work with the corp model. The proj tables have a corp_id, yet I keep getting corp_id is not an attribute when I attempt it with using .value().get() for the proj object. I don't understand how to implement grzgrzgrz3's answer either. I usually work more with JS, HTML, and CSS, and I am new to Django/python for web development.

So any suggestions to make this more efficient would be great. Thank!!

Upvotes: 0

Views: 1923

Answers (3)

Charles Williams
Charles Williams

Reputation: 573

My answer, as described up above. This is what worked for me.

   def ProjDetails(request):
    def date_handler(obj):
        return obj.strftime("%B %d, %Y") if hasattr(obj, 'strftime') else obj

        proj_id = request.GET['proj_id']
        proj = Proj.objects.get(id=proj_id)
        corp = Corp.objects.get(id=proj.corp.id)
        role_list = ProjRole.objects.filter(proj=proj).all()
        proj = {
        "proj": {
             'title': proj.title,
             'id': proj.id,
             'date': proj.date,
             'description': proj.description
        }
        "roles": [],
        "company": {
             'name': corp.name,
             'pic': unicode(corp.pic),
        }
    }
    for r in role_list:
         proj['roles'].append(r.name)

return HttpResponse(json.dumps(proj, default=date_handler), content_type='application/json; charset=UTF-8')

Upvotes: 0

grzgrzgrz3
grzgrzgrz3

Reputation: 350

Write custom HttpResponse and handle there all not serializable python/django objects.

class HttpJsonResponse(HttpResponse):
    content_type="application/json"


    def __init__(self,data):

        def json_serial(obj):
            """JSON serializer for objects not serializable by default json code"""

            if isinstance(obj, datetime.date):
                serial = obj.isoformat()
                return serial

        json_data = json.dumps(data, indent=4, default=json_serial)
        super(HttpJsonResponse, self).__init__(json_data, self.content_type)

In the example function json_serial converting datetime.date object into string object which is serializable.

*UPDATE

You can mix both answers.

def ProjDetails(request):
    proj_id = request.GET['proj_id']
    proj = Proj.objects.filter(id=proj_id).values().get()
    corp = Corp.objects.filter(id=proj.corp.id).values().get()
    role_list = ProjRole.objects.filter(proj=proj).values().all()
    proj = {
        "proj": proj,
        "roles": role_list,
        "company": corp
    }

    return HttpJsonResponse(proj)

Make sure you are importing datetime module.

import datetime

instead datetime class

import datetime.datetime

Upvotes: 1

Eugene Soldatov
Eugene Soldatov

Reputation: 10135

Django model's instance can't be serialized, you should use values() method to retrieve dict instead of class instance. Also, you can use only() method to retrieve only id field for roles:

proj = Proj.objects.filter(id=proj_id).values().get()
role_list = ProjRole.objects.only("id").filter(proj__id=proj_id)
proj = {
    "proj": proj,
    "roles": role_list
}

Upvotes: 1

Related Questions