2016-04-11 14 views
3

Я пытаюсь закодировать объект в json, используя json.dumps() в Django, однако, когда я передаю объект python, он вызывает эту ошибку.TypeError: объект Python не является JSON serializable

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

Я был в предположении, что даже если JSON может кодировать только определенные типы данных, один из этих типов данных были объектами. Я прочитал еще один вопрос о переполнении стека, что хороший способ обойти это, создав словарь из объекта с помощью .__dict__. Я пробовал это, и он говорит, что один из ключей в моем новом словаре, _state не является сериализуемым. Я не уверен, откуда пришел этот _state ключ, и задавался вопросом, есть ли способ конвертировать мой объект в словарь без этого дополнительного поля, поэтому я могу закодировать его в JSON?

модель:

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) 

вид:

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) 

консоль:

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

Класс namedtuple использует '._asdict()' и возвращает вещь в качестве словаря. Возможно, будет полезно использовать тот же интерфейс для вашего кода. –

+0

@WayneWerner О чем ты говоришь? Модели Django и их сериализация не имеют ничего общего с 'namedtuple' – wim

+0

, возвращающим словарь с помощью метода' ._asdict() '. Я упоминаю 'namedtuple' как источник в стандартной библиотеке, которая уже делает это. Возможно, это не совсем подходит для дела OP, но может выполнить то, что им нужно (или другие, у кого есть * подобная проблема). –

ответ

5

__dict__ содержит все атрибуты экземпляра, но вам не нужен весь лишний багаж - для целей сериализации вас интересуют только поля.

Ваша модель не содержит ничего особенного, поэтому встроенные вспомогательную функцию model_to_dict должно быть достаточно для ваших нужд:

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) 

Вашего пример был прост, только содержащим CharField, BooleanField и ForeignKey все из которых мы может сбрасывать до json тривиально.

Для более сложных моделей вы можете рассмотреть возможность написания собственного serializer. В этом случае я рекомендую использовать популярный django-rest-framework, который выполняет всю работу за вас.

from rest_framework import serializers 

class OrgInviteSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = OrgInvite 
     fields = '__all__' 
+0

Работал как шарм! Я буду помнить об этом. – JBT

0

object не один из этих типов. Словари, списки (возможно, кортежи), float, string, integers, bools и None I считают, что - это типы, которые Python может сериализовать в JSON изначально.

Однако, это похоже на Django has some built-in serializers, который может сработать для вас.

Я предполагаю, что

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

должны работать для вас

+0

Нет, сериализатор ожидает, что набор запросов не будет экземпляром модели. – wim

+0

А ... так что тогда это должно быть больше, чем просто результат. –

+1

Итак, вы можете сделать 'OrgInvite.objects.filter (token = 100)', чтобы получить запрос. – ozgur

1

Если вы invite.__dict__, он собирается дать вам словарь всех данных, относящихся к одному invite объекта. Однако значения dict не обязательно являются примитивными типами, но и объекты (ModelState - это только один из них). Сериализация, которая не только не будет работать, потому что json не принимает объекты python, но вы также можете сериализовать много метаданных, которые не используются.

Отъезд json official website, чтобы узнать, какие типы данных являются сериализуемыми json. Исправление будет либо с использованием django model serializer, либо вручную создать dict, что в соответствии с json-форматом.

Смежные вопросы