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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With