web-dev-qa-db-fra.com

TypeError: l'objet Python n'est pas sérialisable JSON

J'essaie de coder un objet dans json en utilisant json.dumps() dans Django. Cependant, lorsque je passe dans un objet python, cette erreur est générée. 

TypeError: <OrgInvite: OrgInvite object> is not JSON serializable

J'avais supposé que, même si JSON ne peut coder que certains types de données, l'un de ces types de données était des objets. J'ai lu une autre question sur Stack Overflow selon laquelle un bon moyen de contourner ce problème consiste à créer un dictionnaire à partir de l'objet à l'aide de .__dict__. J'ai essayé ceci et indique que l'une des clés de mon nouveau dictionnaire, _state, n'est pas sérialisable. Je ne sais pas d'où provient cette clé _state. Je me demandais s'il existait un moyen de convertir mon objet en dictionnaire sans ce champ supplémentaire afin de pouvoir le coder au format JSON.

modèle:

class OrgInvite(models.Model):
    token = models.CharField(max_length=16, unique=True, null=False)
    account_id = models.ForeignKey(Account, on_delete=models.CASCADE, null=False)
    org_id = models.ForeignKey(Org, on_delete=models.CASCADE, null=False)
    used = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    name = models.CharField(max_length=70)
    email = models.CharField(max_length=255)

vue: 

def get_invite(token):
    if not token:
        raise Exception("Invitation token is not specified")

    invitation = OrgInvite.objects.get(token=token)
    if not invitation:
        raise Exception("Invitation token is invalid.")

    return invitation

def invite_accept_redirect(token):
    # """ -Redirects to the accept invite frontend view with pre-fetched data. """

    try:
        invite = get_invite(token)
        if not invite:
            raise Exception("Invitation token is invalid")
        if invite.used:
            invite = {'used': True}
    except:
        invite = {'invalid': True}
        raise Exception("Resource not found.")

    base = "home/accept"

    url = '{}/{}?data={}'.format(base, token, urllib.quote_plus(json.dumps(invite.__dict__)))

    return redirect(url)

console:

>>> oi = OrgInvite.objects.get(token=100) 
>>> oi
<OrgInvite: OrgInvite object>
>>> oix = oi.__dict__
>>> oix
{'used': False, 'name': u'', '_state': <Django.db.models.base.ModelState object at 0x10377a610>, 'email': u'', 'token': u'100', 'org_id_id': 101, 'account_id_id': 301, 'is_admin': False, 'id': 1}
>>> json.dumps(oix)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Django.db.models.base.ModelState object at 0x10377a610> is not JSON serializable
5
JBT

Le __dict__ donne tous les attributs de l'instance, mais vous ne voulez pas tout ce bagage supplémentaire. Aux fins de la sérialisation, vous ne vous intéressez qu'aux champs. 

Votre modèle ne contient rien de spécial, la fonction d'assistance intégrée model_to_dict devrait donc suffire à vos besoins:

import json
from Django.forms.models import model_to_dict

oi = OrgInvite.objects.get(token=100) 
oi_dict = model_to_dict(oi)
oi_serialized = json.dumps(oi_dict)

Votre exemple était simple, ne contenant que CharField, BooleanField et ForeignKey, que nous pouvons vider de manière triviale vers json

Pour les modèles plus complexes, vous pouvez envisager d’écrire votre propre sérialiseur . Dans ce cas, je recommande d'utiliser le populaire Django-rest-framework qui fait tout le travail pour vous. 

from rest_framework import serializers

class OrgInviteSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrgInvite
        fields = '__all__'
5
wim

Si vous faites invite.__dict__, il vous donnera un dictionnaire de toutes les données relatives à un objet invite. Cependant, les valeurs de dict ne sont pas nécessairement des types primitifs, mais également des objets (ModelState n'en est qu'un). Une sérialisation qui ne fonctionnerait pas, car json n'accepte pas les objets python, mais vous pouvez également sérialiser de nombreuses métadonnées non utilisées.

Consultez site officiel de json pour voir quels types de données json est sérialisable. Le correctif consisterait à utiliser Django model serializer ou à créer manuellement un dict conforme au format JSON.

1
Shang Wang

object n'est pas l'un de ces types. Dictionnaires, listes (peut-être des tuples), floats, chaînes, entiers, bools et None I crois sont les types que Python peut sérialiser en JSON de manière native.

Cependant, il semble que Django possède des sérialiseurs intégrés qui peuvent fonctionner pour vous.

Je devine que 

from Django.core import serializers
data = serializers.serialize("json", OrgInvite.objects.filter(token=100))

devrait travailler pour vous

0
Wayne Werner