2010-02-11 27 views
34

¿Cómo puede ser que se haya producido este error? Entré en esto:Django: "TypeError: [] no es serializable por JSON" ¿Por qué?

def json(self): 
    return json.dumps(
     { 
      'items': self.items 
     } 
    ) 

y consiguió que el error (porque self.items fue un conjunto de consultas vacía (Django)

pero luego,

def json(self): 
    return json.dumps(
     { 
      'items': [] # Pass in empty list to prove that the error was idiotic. 
     } 
    ) 

funcionó bien (que al menos demuestra que el mensaje de error es inútil)

Esto es porque el conjunto de consulta define repr() y devuelve '[]' como una cadena cuando está vacía o algo ¿Así de ridículo?

+3

¿Por qué define una función con el mismo nombre que un módulo que está utilizando? –

+0

@gnibbler No es una función. Es un método y lo estoy usando como @property (no incluí eso en mi ejemplo). – orokusaki

+3

Me encanta mirar lo satisfecho que estaba, '... el error fue idiota. – orokusaki

Respuesta

54

Los conjuntos de consulta no se pueden serializar desde el primer momento. Si prueba list(self.items) en lugar de solo self.items, eso debería funcionar siempre que los elementos en sí mismos sean serializables por JSON.

Actualización: Se generará una excepción aunque no esté vacía. No creo que sea aceptado como un error de Django, aunque por supuesto puedes intentarlo; la respuesta más simple es forzar la evaluación usando list(qs), como ya he dicho.

+1

+1. Esta es la respuesta. Está utilizando list (queryset) para forzar la evaluación del conjunto de consulta de inmediato. Los datos subyacentes, en forma de lista, son serializables; el queryset en sí no es http://docs.djangoproject.com/en/dev/ref/models/querysets/#id1 – cethegeek

+2

Buena respuesta. Gracias. Por cierto, esto parece un error. Voy a comenzar un boleto para eso. Los serializadores de Django están destinados a serializar los conjuntos de consulta Django. Si genera una excepción cuando está vacía, es un error. – orokusaki

+1

@orokusaki, esto no se siente como un error para mí. A veces quieres objetos. A veces quieres cadenas. Django te deja elegir. Aquí hay una alternativa más pitonica que funciona para mí, para todos los campos de Django: '[str (obj) para obj en Model.objects.values ​​()]' [ver a continuación] (http://stackoverflow.com/a/14653384/ 623735) – hobs

5

Esto es muy frustrante. La serialización de Django se queja de todo lo que no es un conjunto de consultas y json.dumps se queja de los objetos del soporte ORM de Django.

>>> from cluster.models import Account 
>>> import json 
>>> json.dumps(Account.objects.all()[0]) 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 231, in dumps 
    return _default_encoder.encode(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 201, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 264, in iterencode 
    return _iterencode(o, 0) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 178, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
TypeError: <Account: 9de5-2653-000d-81a3 => [email protected]> is not JSON serializable 

Versus

>>> serializers.serialize("json", [clusters]) 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/serializers/__init__.py", line 91, in serialize 
    s.serialize(queryset, **options) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/serializers/base.py", line 41, in serialize 
    for field in obj._meta.local_fields: 
AttributeError: 'QuerySet' object has no attribute '_meta' 
4

Como se señaló Vinay, igual que lances a una lista, la serialización menudo sigue fallando. Para mí, la serialización falla en los elementos DateTimeField (datetime.datetime objetos), incluso si pido un ValuesQuerySet (similar a una lista) con .values(). La solución para mí fue una comprensión simple.

json.dumps([str(obj) for obj in Model.objects.values()]); 

En su caso, eso sería

return json.dumps({k: str(v) for k, v in self.__dict__.items()}) 

La magia de str salva el día. El repr incorporado también puede ser útil si necesita información de tipo de objeto en su serialización.

Cuestiones relacionadas