2013-04-08 4 views
15

Je veux sérialisation mon queryset, et je veux dans un format que cette vue des sorties:sortie Django QuerySet JSON

class JSONListView(ListView): 
    queryset = Users.objects.all() 

    def get(self, request, *args, **kwargs): 
     return HttpResponse(json.dumps({'data': [['bar','foo','bar','foo'],['foo','bar','foo','bar']]}, indent=4), content_type='application/json') 

Je ne sais tout simplement pas comment sortir le queryset au lieu des données manuelle dans l'exemple.

J'ai essayé

json.dumps({"data": self.get_queryset()}) 

et

serializers.serialize("json", {'data': self.get_queryset()}) 

mais il ne fonctionnera pas. Qu'est-ce que je fais mal? Dois-je créer un codeur JSON personnalisé?

+0

Qu'est-ce qui n'a pas fonctionné? Avez-vous lu [les docs sur les séries de requêtes de sérialisation] (https://docs.djangoproject.com/fr/dev/topics/serialization/)? J'imagine que le problème est avec les relations ForeignKey/M2M dans votre modèle –

Répondre

24

Cela n'a pas fonctionné, car les QuerySets ne sont pas sérialisables JSON.

1) En cas de json.dumps vous devez convertir votre QuerySet explicitement à JSON objets sérialisables:

class Model(model.Model): 
    def as_dict(self): 
     return { 
      "id": self.id, 
      # other stuff 
     } 

Et la sérialisation:

dictionaries = [ obj.as_dict() for obj in self.get_queryset() ] 
return HttpResponse(json.dumps({"data": dictionaries}), content_type='application/json') 

2) En cas de serializers. Les sérialiseurs acceptent l'objet sérialisable JSON ou QuerySet, mais un dictionnaire contenant un QuerySet n'est ni l'un ni l'autre. Essayez ceci:

serializers.serialize("json", self.get_queryset()) 

En savoir plus ici:

https://docs.djangoproject.com/en/dev/topics/serialization/

+0

C'est une bonne réponse. Je vais aller avec la première solution. Dans votre deuxième solution, comment est-il possible d'attribuer une «clé» aux données? Devrait-il être quelque chose comme {"data": serializers.serialize ("json", self.get_queryset())}? – user2232982

+1

@ user2232982 Je ne suis pas sûr d'être honnête, j'utilise toujours la première technique. :) Votre solution n'est pas bonne, parce que vous obtenez un dictionnaire avec une chaîne JSON, donc vous devez toujours le sérialiser pour obtenir un double objet sérialisé. : O – freakish

+0

La première technique est une invention de la roue. – Alex78191

13

Exemple simple:

from django.http import JsonResponse 

def some_view(request): 
    data = list(SomeModel.objects.values()) 
    return JsonResponse(data, safe=False) # or JsonResponse({'data': data}) 

Ou une autre approche:

from django.core import serializers 
from django.http import HttpResponse 

def some_view(request): 
    qs = SomeModel.objects.all() 
    qs_json = serializers.serialize('json', qs) 
    return HttpResponse(qs_json, content_type='application/json') 

Dans ce réponse de cas sera peu différent (sans tiret par défaut):

[ 
    { 
     "model": "some_app.some_model", 
     "pk": 1, 
     "fields": { 
      "name": "Ivan", 
      "age": 35, 
      ... 
     } 
    }, 
    ... 
] 

Je dois dire qu'il est bon d'utiliser quelque chose comme marshmallow pour la sérialisation d'objets.

Et il y a quelques notes comment faire votre point de vue aussi vite que possible pour une meilleure performance:

  • si votre utilisation queryset en page est grand;
  • d'utiliser objects.values() pour spécifier la liste des champs obligatoires pour éviter la sérialisation et l'envoi au client des champs de modèle inutiles (vous pouvez également passer fields à serializers.serialize);
  • définir approprié settings.CONN_MAX_AGE, par exemple 500 (valeur de documents heroku);
  • vous pouvez utiliser la vue basée sur la fonction pour de meilleures performances (mais le code clair est évidemment préférable à un code légèrement plus rapide, attention);
+0

L'utilisation de 'JsonResponse' avec JSON est incorrecte,' HttpResponse' devrait être utilisé à la place. Si vous utilisez – Alex78191

+0

, je n'aime pas le format de modèle Django avec des fichiers spécifiques '{model:" name.sub ", pk: 1, champs: {, ...}}'. J'aime [simple JSON avec ses propres champs] (https://stackoverflow.com/a/30243413/4854931). – Alex78191

+0

@ Alex78191 merci, vous avez raison. Je m'attendais à ce que les sérialiseurs de Django fonctionnent de la même manière que les sérialiseurs DRF. –

0

Essayez ceci:

class JSONListView(ListView): 
    queryset = Users.objects.all() 


    def get(self, request, *args, **kwargs): 
     data = {} 
     data["users"] = get_json_list(queryset) 
     return JSONResponse(data) 


def get_json_list(query_set): 
    list_objects = [] 
    for obj in query_set: 
     dict_obj = {} 
     for field in obj._meta.get_fields(): 
      try: 
       if field.many_to_many: 
        dict_obj[field.name] = get_json_list(getattr(obj, field.name).all()) 
        continue 
       dict_obj[field.name] = getattr(obj, field.name) 
      except AttributeError: 
       continue 
     list_objects.append(dict_obj) 
    return list_objects 
+0

Donner du code et faire d'autres tâches pour eux, sans expliquer le problème original et la solution utilisée, n'aide pas beaucoup ... – matteeyah

0

Si l'objectif est de construire une API qui vous permettent d'accéder à vos modèles au format JSON je vous recommande d'utiliser le django-restframework qui est un package très populaire dans le Django communauté pour réaliser ce type de tâches.

Il inclut des fonctionnalités utiles telles que Pagination, Définition Sérialiseurs, modèles emboîtés/relations et plus encore. Même si vous ne voulez effectuer que des tâches javascript mineures et des appels Ajax, je vous suggère de créer une API appropriée en utilisant Django Rest Framework au lieu de définir manuellement la réponse JSON.