web-dev-qa-db-fra.com

Comment passer des champs de modèle à un objet JsonResponse

Django 1.7 a introduit les objets JsonResponse , que j'essaie d'utiliser pour renvoyer une liste de valeurs à ma demande ajax.

Je veux passer

>>> 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'}]

à un objet JsonResponse.

Cependant, mes tentatives échouent.

>>> 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

Cela est probablement dû à la structure différente des données de Genre.objects.values().

Comment cela pourrait-il être fait correctement?

[Éditer]

Avec safe=False Je reçois

>>> 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

Ce qui fonctionne est

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

Mais n'y a-t-il pas une meilleure façon de générer un dict à partir d'un objet Model?

19
speendo

Pour référence future, .values() renvoie un ValuesQuerySet qui se comporte comme un itérable plein de dictionnaires, donc l'utilisation de list() créera une nouvelle instance d'un list avec tous les dictionnaires qu'il contient. Avec cela, vous pouvez créer un nouveau dict et le sérialiser.

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

IIRC, il n'est pas sûr d'avoir un objet JSON qui a une liste en tant que root et c'est probablement pourquoi Django se plaint. Je n'ai pu trouver aucune référence à ce sujet maintenant pour fournir une source, désolé.

20
Tiago