Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass model fields to a JsonResponse object

Tags:

Django 1.7 introduced the JsonResponse objects, which I try to use to return a list of values to my ajax request.

I want to pass

>>> Genre.objects.values('name', 'color') [{'color': '8a3700', 'name': 'rock'}, {'color': 'ffff00', 'name': 'pop'}, {'color': '8f8f00', 'name': 'electronic'}, {'color': '9e009e', 'name': 'chillout'}, {'color': 'ff8838', 'name': 'indie'}, {'color': '0aff0a', 'name': 'techno'}, {'color': 'c20000', 'name': "drum'n'bass"}, {'color': '0000d6', 'name': 'worldmusic'}, {'color': 'a800a8', 'name': 'classic'}, {'color': 'dbdb00', 'name': 'hiphop'}] 

to a JsonResponse object.

However, my attempts fail.

>>> JsonResponse({'foo': 'bar', 'blib': 'blab'}) # works <django.http.response.JsonResponse object at 0x7f53d28bbb00>  >>> JsonResponse(Genre.objects.values('name', 'color')) # doesn't work Traceback (most recent call last):   File "<console>", line 1, in <module>   File "/home/marcel/Dokumente/django/FlushFM/env/lib/python3.4/site-packages/django/http/response.py", line 476, in __init__     raise TypeError('In order to allow non-dict objects to be ' TypeError: In order to allow non-dict objects to be serialized set the safe parameter to False 

This is probably due to the different data structure of Genre.objects.values().

How would this be done right?

[edit]

With safe=False I get

>>> JsonResponse(Genre.objects.values('name', 'color'), safe=False) Traceback (most recent call last):   File "<console>", line 1, in <module>   File "/home/marcel/Dokumente/django/FlushFM/env/lib/python3.4/site-packages/django/http/response.py", line 479, in __init__     data = json.dumps(data, cls=encoder)   File "/usr/lib/python3.4/json/__init__.py", line 237, in dumps     **kw).encode(obj)   File "/usr/lib/python3.4/json/encoder.py", line 192, in encode     chunks = self.iterencode(o, _one_shot=True)   File "/usr/lib/python3.4/json/encoder.py", line 250, in iterencode     return _iterencode(o, 0)   File "/home/marcel/Dokumente/django/FlushFM/env/lib/python3.4/site-packages/django/core/serializers/json.py", line 109, in default     return super(DjangoJSONEncoder, self).default(o)   File "/usr/lib/python3.4/json/encoder.py", line 173, in default     raise TypeError(repr(o) + " is not JSON serializable") TypeError: [{'color': '8a3700', 'name': 'rock'}, {'color': 'ffff00', 'name': 'pop'}, {'color': '8f8f00', 'name': 'electronic'}, {'color': '9e009e', 'name': 'chillout'}, {'color': 'ff8838', 'name': 'indie'}, {'color': '0aff0a', 'name': 'techno'}, {'color': 'c20000', 'name': "drum'n'bass"}, {'color': '0000d6', 'name': 'worldmusic'}, {'color': 'a800a8', 'name': 'classic'}, {'color': 'dbdb00', 'name': 'hiphop'}] is not JSON serializable 

What works is

>>> JsonResponse(list(Genre.objects.values('name', 'color')), safe=False) <django.http.response.JsonResponse object at 0x7f53d28bb9e8> 

But isn't there a better way to generate a dict out of a Model object?

like image 710
speendo Avatar asked Sep 26 '14 19:09

speendo


2 Answers

For future reference, .values() returns a ValuesQuerySet that behaves like a iterable full of dictionaries, so using the list() will make a new instance of a list with all the dictionaries in it. With that, you can create a new dict and serialize that.

response = JsonResponse(dict(genres=list(Genre.objects.values('name', 'color')))) 

IIRC, it's not safe to have a JSON object that has a list as root and that's probably why Django is complaining. I couldn't find any reference about that now to provide a source, sorry.

like image 73
Tiago Avatar answered Oct 25 '22 17:10

Tiago


To pass nondictionary values to the JsonResponse as you retrieved with Genres.object.values('name','color') you can simple set the safe argument to false and it will return JSON.

from django.http import JsonResponse  def django_json(request):     data = Genres.object.values('name','color')     return JsonResponse(data, safe=False) 

That should return a list of JSON of the values you specified. Check out my article How to Return a Json Response with Django for more detailed info on how this works.

Alternatively, if you would like to return a queryset back as JSON you can use Djangos core serializer like this:

from django.core.serializers import serialize from django.http import JsonResponse from .models import Genre  def django_models_json(request):     qs = Genre.objects.all()     data = serialize("json", qs, fields=('name', 'color'))     return JsonResponse(data) 

This will return the same as above.

like image 22
Royalbishop101 Avatar answered Oct 25 '22 16:10

Royalbishop101