198 votes

Comment sérialiser une instance de modèle dans Django ?

Il existe beaucoup de documentation sur la façon de sérialiser un Model QuerySet mais comment sérialiser en JSON les champs d'une Instance de Modèle ?

0 votes

Bien qu'il semble que vous puissiez sérialiser un queryset de 1 objet, vous ne pouvez pas utiliser les classes de django.core pour le faire. Y a-t-il une raison particulière de ne pas utiliser la sérialisation du queryset ?

1 votes

Le sérialiseur queryset enveloppe le résultat dans deux couches de plus que nécessaire. Vous devez donc faire data[0].fields.name au lieu de data.name.

0 votes

C'est ce que je pensais. J'ai rencontré le même problème lorsque j'écrivais une interface GWT pour un backend django. On dirait que David pourrait être sur quelque chose.

284voto

xaralis Points 1206

Vous pouvez facilement utiliser une liste pour envelopper l'objet requis et c'est tout ce dont les sérialiseurs de django ont besoin pour le sérialiser correctement, par ex :

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])

11 votes

Mais en réponse, vous devez indexer l'élément zéro de l'objet JSON pour accéder à l'objet sérialisé. Juste quelque chose à noter.

13 votes

Et pourquoi ne pas sérialiser tous les objets référencés avec l'objet Root ?

2 votes

Ne voulez-vous pas [0] à la fin de votre dernière ligne, comme @DavorLucic l'a suggéré ? Et pas besoin de virgule de fin dans votre liste littérale (pour l'amour de PEP8 ;).

46voto

Julian Points 1517

Pour éviter le wrapper de tableau, supprimez-le avant de renvoyer la réponse :

import json
from django.core import serializers

def getObject(request, id):
    obj = MyModel.objects.get(pk=id)
    data = serializers.serialize('json', [obj,])
    struct = json.loads(data)
    data = json.dumps(struct[0])
    return HttpResponse(data, mimetype='application/json')

J'ai également trouvé ce post intéressant sur le sujet :

http://timsaylor.com/convert-django-model-instances-to-dictionaries

Il utilise django.forms.models.model_to_dict, qui semble être l'outil parfait pour ce travail.

9 votes

Si c'est la meilleure façon de sérialiser un seul modèle dans django, alors c'est horrible car on ne devrait pas avoir besoin de désérialiser le json et de le sérialiser à nouveau.

0 votes

@Herbert, peut-être. Mais c'est ainsi. Si vous avez une meilleure solution, je suis tout ouïe. Cela ne devrait pas avoir beaucoup d'inconvénients pratiques, car la récupération et le dé/réencodage d'un seul objet ne devraient pas être si gourmands en ressources. Faites-en une fonction d'aide ou étendez/mélangez-la avec vos objets comme une nouvelle méthode si vous voulez cacher l'horreur.

1 votes

Cacher l'horreur n'est pas le problème et peut-être même pas cette solution ; ce qui me surprend, c'est que c'est la meilleure façon pour django de le faire.

12voto

David Berger Points 5459

Il semble que votre question porte sur la sérialisation de la structure des données d'une instance de modèle Django à des fins d'interopérabilité. Les autres posters sont corrects : si vous voulez que le formulaire sérialisé soit utilisé avec une application python qui peut interroger la base de données via l'api de Django, alors vous voudriez sérialiser un queryset avec un objet. Si, d'autre part, ce dont vous avez besoin est un moyen de regonfler l'instance du modèle quelque part ailleurs sans toucher à la base de données ou sans utiliser Django, alors vous avez un peu de travail à faire.

Voilà ce que je fais :

D'abord, j'utilise demjson pour la conversion. C'est ce que j'ai trouvé en premier, mais ce n'est peut-être pas le meilleur. Mon implémentation dépend d'une de ses caractéristiques, mais il devrait y avoir des moyens similaires avec d'autres convertisseurs.

Deuxièmement, mettez en place un json_equivalent sur tous les modèles que vous pourriez avoir besoin de sérialiser. Il s'agit d'une méthode magique pour demjson mais c'est probablement une chose à laquelle vous devez penser, quelle que soit la mise en œuvre que vous choisissez. L'idée est de retourner un objet qui est directement convertible en json (c'est-à-dire un tableau ou un dictionnaire). Si vous voulez vraiment faire cela automatiquement :

def json_equivalent(self):
    dictionary = {}
    for field in self._meta.get_all_field_names()
        dictionary[field] = self.__getattribute__(field)
    return dictionary

Cela ne vous sera utile que si vous disposez d'une structure de données complètement plate (aucune ForeignKeys uniquement des chiffres et des chaînes de caractères dans la base de données, etc.) Sinon, vous devriez sérieusement réfléchir à la bonne façon d'implémenter cette méthode.

Troisièmement, appelez demjson.JSON.encode(instance) et tu as ce que tu veux.

0 votes

Je n'ai pas encore essayé le code mais je voulais juste signaler quelques erreurs dans celui-ci. C'est instance._meta.get_all_field_names() et obtenir un attribut est une fonction et devrait donc avoir () et non [].

0 votes

En plus de FK, cela ne fonctionnera pas pour les champs de type datetime (à moins qu'il n'y ait de la magie dans demjson.JSON.encode)

9voto

benlast Points 131

Si vous vous demandez comment sérialiser un seul objet à partir d'un modèle et que vous connaître vous n'allez obtenir qu'un seul objet dans le queryset (par exemple, en utilisant objects.get), alors utilisez quelque chose comme :

import django.core.serializers
import django.http
import models

def jsonExample(request,poll_id):
    s = django.core.serializers.serialize('json',[models.Poll.objects.get(id=poll_id)])
    # s is a string with [] around it, so strip them off
    o=s.strip("[]")
    return django.http.HttpResponse(o, mimetype="application/json")

ce qui vous permettrait d'obtenir quelque chose de cette forme :

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}

0 votes

Mais cela supprimera tous les crochets, pas seulement ceux de l'extérieur. C'est mieux ? "o=s[1:-1]" ?

5voto

davidchambers Points 3048

J'ai résolu ce problème en ajoutant une méthode de sérialisation à mon modèle :

def toJSON(self):
    import simplejson
    return simplejson.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))

Voici l'équivalent verbeux pour ceux qui n'aiment pas les phrases toutes faites :

def toJSON(self):
    fields = []
    for field in self._meta.fields:
        fields.append(field.name)

    d = {}
    for attr in fields:
        d[attr] = getattr(self, attr)

    import simplejson
    return simplejson.dumps(d)

_meta.fields est une liste ordonnée de champs du modèle auxquels on peut accéder à partir des instances et du modèle lui-même.

3 votes

Bien que l'idée puisse sembler bonne au premier abord, il convient de souligner que l'utilisation de cette approche a des conséquences. Vous liez une sortie de sérialisation spécifique à votre modèle.

0 votes

@JonasGeiregat puisque cette méthode est définie sur la base d'un modèle à l'autre, qu'y a-t-il de mal à cette approche ? Malheureusement, cela semble être la seule façon de retourner un objet json qui contient à la fois les champs et la clé primaire de l'instance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X