Как вернуть правильный json из результата sql alchemy с подключением? [Дубликат]

используете ли вы конфигурацию SMTP для отправки своей электронной почты? попробуйте вместо этого использовать phpmailer. вы можете загрузить библиотеку из https://github.com/PHPMailer/PHPMailer . Я создал электронную почту, отправив этот путь:

function send_mail($email, $recipient_name, $message='')
{
    require("phpmailer/class.phpmailer.php");

    $mail = new PHPMailer();

    $mail->CharSet="utf-8";
    $mail->IsSMTP();                                      // set mailer to use SMTP
    $mail->Host = "mail.example.com";  // specify main and backup server
    $mail->SMTPAuth = true;     // turn on SMTP authentication
    $mail->Username = "myusername";  // SMTP username
    $mail->Password = "p@ssw0rd"; // SMTP password

    $mail->From = "me@walalang.com";
    $mail->FromName = "System-Ad";
    $mail->AddAddress($email, $recipient_name);

    $mail->WordWrap = 50;                                 // set word wrap to 50 characters
    $mail->IsHTML(true);                                  // set email format to HTML (true) or plain text (false)

    $mail->Subject = "This is a Sampleenter code here Email";
    $mail->Body    = $message;
    $mail->AltBody = "This is the body in plain text for non-HTML mail clients";    
    $mail->AddEmbeddedImage('images/logo.png', 'logo', 'logo.png');
    $mail->addAttachment('files/file.xlsx');

    if(!$mail->Send())
    {
       echo "Message could not be sent. 

"; echo "Mailer Error: " . $mail->ErrorInfo; exit; } echo "Message has been sent"; }

545
задан Jeff Wilbert 10 April 2016 в 02:09
поделиться

22 ответа

Есть ли у вас представление о ожидаемом выходе? Напр. это будет?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

В этом случае вы можете просто называть json.dumps(f.__dict__).

Если вам нужен более индивидуальный вывод, вам придется подклассы JSONEncoder и реализовать свою собственную сериализацию.

Для тривиального примера см. ниже.

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

Затем вы передаете этот класс в метод json.dumps() как cls kwarg:

json.dumps(cls=MyEncoder)

Если вы также хотите декодировать, вам нужно будет поставить пользовательский object_hook в класс JSONDecoder . Например,

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 
393
ответ дан Bear Brown 22 August 2018 в 08:53
поделиться
  • 1
    Использование __dict__ не будет работать во всех случаях. Если атрибуты не были установлены после создания объекта, __dict__ могут быть не заполнены полностью. В приведенном выше примере вы в порядке, но если у вас есть атрибуты класса, которые вы также хотите кодировать, они не будут указаны в __dict__, если они не были изменены в вызове класса __init__ или каким-либо другим способом после того, как объект был создан. – Kris Hardy 29 December 2011 в 18:41
  • 2
    +1, но функция from_json(), используемая как объект-крючок, должна иметь оператор else: return json_object, поэтому он также может иметь дело с общими объектами. – jogojapan 19 March 2013 в 09:51
  • 3
    @KrisHardy __dict__ также не работает, если вы используете __slots__ в новом классе стиля. – badp 13 December 2013 в 19:53
  • 4
    это быстрее, чем использование cPickle? – ealeon 26 May 2015 в 23:08
  • 5
    Вы можете использовать пользовательский JSONEncoder, как указано выше, для создания настраиваемого протокола, например, проверку существования метода __json_serializable__ и вызов его для получения сериализуемого JSON представления объекта. Это соответствовало бы другим паттернам Python, таким как __getitem__, __str__, __eq__ и __len__. – jpmc26 15 July 2015 в 00:53

Большинство ответов связаны с изменением вызова на json.dumps (), что не всегда возможно или желательно (это может произойти, например, в компоненте framework).

Если вы хотите быть в состоянии для вызова json.dumps (obj) как есть, тогда простое решение наследуется от dict:

class FileItem(dict):
    def __init__(self, fname):
        dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f)  #No need to change anything here

Это работает, если ваш класс является просто базовым представлением данных, потому что для более сложных вещей вы всегда можете задавать ключи явно .

45
ответ дан andyhasit 22 August 2018 в 08:53
поделиться
  • 1
    Это действительно может быть хорошим решением :) Я считаю, что для моего случая это так. Преимущества: вы сообщаете «форму». объекта путем создания класса с init, он по сути сериализуется и выглядит интерпретируемым как repr . – PascalVKooten 22 September 2016 в 19:41
  • 2
    – PascalVKooten 22 September 2016 в 19:46
  • 3
    Это было здорово для меня, потому что я был в списке. Tks! – Ana Franco 9 May 2018 в 20:50
  • 4
    – Christian G. 24 August 2018 в 13:52

Мне нравится ответ Онура , но он будет расширяться, чтобы включить опциональный метод toJSON() для сериализации объектов:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)
27
ответ дан Community 22 August 2018 в 08:53
поделиться
  • 1
    Я нашел, что это лучший баланс между использованием существующего json.dumps и внедрением пользовательской обработки. Благодаря! – Daniel Buckmaster 15 April 2015 в 00:52
  • 2
    ваше имя подразумевает, что вы любите JSON-вопросы ...;) – kmonsoor 3 December 2015 в 00:41
  • 3
    Мне это действительно нравится; но вместо try-catch, вероятно, сделает что-то вроде if 'toJSON' in obj.__attrs__(): ..., чтобы избежать молчащего сбоя (в случае сбоя в JSON () по какой-то другой причине, чем он не существует) ... сбой, который потенциально приводит к повреждению данных. – thclark 22 November 2017 в 19:29

Вот мои 3 цента ... Это демонстрирует явную сериализацию json для древовидного объекта python. Примечание. Если вам действительно нужен такой код, вы можете использовать класс twisted FilePath .

import json, sys, os

class File:
    def __init__(self, path):
        self.path = path

    def isdir(self):
        return os.path.isdir(self.path)

    def isfile(self):
        return os.path.isfile(self.path)

    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]

    def getsize(self):        
        return os.path.getsize(self.path)

    def getModificationTime(self):
        return os.path.getmtime(self.path)

def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d

folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)
1
ответ дан Dan Brough 22 August 2018 в 08:53
поделиться

Я придумал свое решение. Используйте этот метод, передайте любой документ ( dict , list , ObjectId и т. Д.) Для сериализации.

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc

    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc

    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc

    # Use any other custom serializting stuff here...

    # For the rest of stuff
    return doc
0
ответ дан Dewsworld 22 August 2018 в 08:53
поделиться

Для более сложных классов вы можете рассмотреть инструмент jsonpickle :

jsonpickle - это библиотека Python для сериализации и десериализации сложных объектов Python в JSON и из JSON.

Стандартные библиотеки Python для кодирования Python в JSON, такие как json, simplejson и demjson stdlib, могут обрабатывать только примитивы Python, которые имеют прямой эквивалент JSON (например, dicts, lists, string, ints и т. д.). ). jsonpickle строит поверх этих библиотек и позволяет сериализовать более сложные структуры данных в JSON. jsonpickle очень настраивается и расширяется, позволяя пользователю выбирать бэкэнд JSON и добавлять дополнительные бэкэнды.

(jsonpickle on PyPi)

107
ответ дан gecco 22 August 2018 в 08:53
поделиться
  • 1
  • 2
    jsonpickle потрясающе. Он отлично работал для огромного, сложного, грязного объекта со многими уровнями классов – wisbucky 4 March 2016 в 19:23
  • 3
    есть ли пример правильного способа сохранить это в файле? В документации только показано, как кодировать и декодировать объект jsonpickle. Кроме того, это не было способно расшифровывать диктофон dicts, содержащий pandas dataframes. – user5359531 16 August 2016 в 17:14
  • 4
    @ user5359531 вы можете использовать obj = jsonpickle.decode(file.read()) и file.write(jsonpickle.encode(obj)). – Kilian Batzner 2 January 2017 в 09:04
  • 5
    Вопрос специально для django: использует ли jsonpickle для сериализации данных сеанса ту же уязвимость, что и pickle? (как описано здесь docs.djangoproject.com/en/1.11/topics/http/sessions/… )? – Paul Bormans 23 June 2017 в 14:24

Существует много подходов к этой проблеме. «ObjDict» (pip install objdict) - это другое. Существует акцент на предоставлении javascript-подобных объектов, которые также могут действовать как словари, чтобы лучше обрабатывать данные, загруженные из JSON, но есть и другие функции, которые могут быть полезны. Это дает другое альтернативное решение исходной проблемы.

0
ответ дан innov8 22 August 2018 в 08:53
поделиться

Я решил использовать декораторы для решения проблемы сериализации объекта datetime. Вот мой код:

#myjson.py
#Author: jmooremcc 7/16/2017

import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
    from myjson import json

json.dumps and json.dump will then correctly serialize datetime and date 
objects
"""

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        serial = str(obj)
        return serial
    raise TypeError ("Type %s not serializable" % type(obj))


def FixDumps(fn):
    def hook(obj):
        return fn(obj, default=json_serial)

    return hook

def FixDump(fn):
    def hook(obj, fp):
        return fn(obj,fp, default=json_serial)

    return hook


json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)


if __name__=="__main__":
    today=datetime.now()
    data={'atime':today, 'greet':'Hello'}
    str=json.dumps(data)
    print str

Импортируя вышеуказанный модуль, мои другие модули используют json обычным способом (без указания ключевого слова по умолчанию) для сериализации данных, содержащих объекты времени даты. Код datetime serializer автоматически вызывается для json.dumps и json.dump.

0
ответ дан John Moore 22 August 2018 в 08:53
поделиться

Этот класс может сделать трюк, он преобразует объект в стандартный json.

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

use:

Serializer.serialize(my_object)

работает в python2.7 и python3.

4
ответ дан Lost Koder 22 August 2018 в 08:53
поделиться
  • 1
    Мне понравился этот метод больше всего. Я столкнулся с проблемами при попытке сериализации более сложных объектов, чьи члены / методы не сериализуемы. Вот моя реализация, которая работает с большим количеством объектов: `` `class Serializer (object): @staticmethod def serialize (obj): def check (o): для k, v в o .__ dict __. Items (): try: _ = json .dumps (v) o .__ dict __ [k] = v кроме TypeError: o .__ dict __ [k] = str (v) return o return json.dumps (check (obj) .__ dict__, indent = 2) `` ` – Will Charlton 11 November 2017 в 06:34

Если вы не против установки пакета для него, вы можете использовать json-tricks :

pip install json-tricks

После этого вам просто нужно импортировать dump(s) из json_tricks вместо json, и он обычно работает:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

, который даст

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

И это в основном это!


Это будет отлично работать в целом. Существуют некоторые исключения, например. если в __new__ происходят особые вещи, или происходит больше метаклассической магии.

Очевидно, что загрузка также работает (в противном случае в чем смысл):

from json_tricks import loads
json_str = loads(json_str)

Это предполагает, что module_name.test_class.MyTestCls могут быть импортированы и не изменены несовместимыми способами. Вы вернете экземпляр, а не какой-либо словарь или что-то еще, и он должен быть идентичной копией того, который вы сбросили.

Если вы хотите настроить, как что-то получает (де) сериализован, вы можете добавить специальные методы для вашего класса, например:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37

        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}

        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

, который в качестве примера сериализует только часть параметров атрибутов.

И как бесплатный бонус, вы получаете (de) сериализация массивов numpy, date & amp; временами, упорядоченные карты, а также возможность включать комментарии в json.

Отказ: я создал json_tricks , потому что у меня была та же проблема, что и вы.

1
ответ дан Mark 22 August 2018 в 08:53
поделиться

jaraco дал довольно аккуратный ответ. Мне нужно было исправить некоторые незначительные вещи, но это работает:

Код

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }

    to_json = __json__  # supported by simplejson

    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj

# Dumping and loading
import simplejson

obj = MyCustom()
obj.a = 3
obj.b = 4

json = simplejson.dumps(obj, for_json=True)

# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)

# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

Обратите внимание, что нам нужно выполнить два шага для загрузки. На данный момент свойство __python__ не используется.

Насколько это распространено?

Используя метод AlJohri , я проверяю популярность подходов:

Сериализация (Python -> JSON):

Дезициализация (JSON -> Python):

1
ответ дан Martin Thoma 22 August 2018 в 08:53
поделиться

jsonweb кажется лучшим решением для меня. См. http://www.jsonweb.info/en/latest/

from jsonweb.encode import to_object, dumper

@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value

>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'
2
ответ дан matthewlent 22 August 2018 в 08:53
поделиться
  • 1
    Он хорошо работает для вложенных объектов? Включая декодирование и кодирование – Simone Zandara 22 December 2015 в 09:43

Вот простое решение для простой функции:

.toJSON() Метод

Вместо сериализуемого класса JSON реализуйте метод сериализатора:

import json

class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

Итак, вы просто вызываете его для сериализации:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

выведет:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}
440
ответ дан Onur Yıldırım 22 August 2018 в 08:53
поделиться
  • 1
    Очень ограничен. Если у вас есть dict {"foo": "bar", "baz": "bat"}, который будет легко сериализоваться в JSON. Если вместо этого у вас есть {& quot; foo & quot;: & quot; bar & quot ;, baz & quot;: MyObject ()}, то вы не можете. Идеальная ситуация заключается в том, что вложенные объекты сериализуются в JSON рекурсивно, а не явно. – Mark E. Haase 22 August 2013 в 19:51
  • 2
    Он по-прежнему будет работать. Вам не хватает o.__dict___. Попробуйте свой собственный пример: class MyObject(): def __init__(self): self.prop = 1 j = json.dumps({ "foo": "bar", "baz": MyObject() }, default=lambda o: o.__dict__) – Onur Yıldırım 22 August 2013 в 23:56
  • 3
    – Jorge Leitão 26 April 2015 в 18:20
  • 4
    @ J.C.Leitão Нет. У вас могут быть два разных класса с одинаковыми полями. Объекты a и b этого класса (возможно, с теми же свойствами) имели бы тот же a.__dict__ / b.__dict__. – Martin Thoma 16 June 2015 в 12:30
  • 5
    Это не работает с экземплярами datetime.datetime. Он выдает следующую ошибку: 'datetime.datetime' object has no attribute '__dict__' – Bruno Finger 17 June 2015 в 12:43

Другим вариантом является перенос JSON-демпинга в свой класс:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

    def __repr__(self):
        return json.dumps(self.__dict__)

Или, что еще лучше, подклассификация класса FileItem из класса JsonSerializable:

import json

class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.toJson()


class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

Тестирование:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'
31
ответ дан Paulo Freitas 22 August 2018 в 08:53
поделиться
  • 1
    Привет, мне не очень нравится этот «пользовательский кодер». подход, было бы лучше, если бы вы могли сделать свой класс json seriazable. Я стараюсь, стараюсь и ничего не пытаюсь. Есть ли идея, как это сделать. Дело в том, что модуль json тестирует ваш класс против встроенных типов python и даже говорит, что для пользовательских классов создайте свой кодер :). Может быть, это подделка? Поэтому я мог бы сделать что-то для своего класса, чтобы он вел себя как простой список для json-модуля? Я стараюсь subclasscheck и instancecheck , но ничего. – bradojevic 15 August 2012 в 13:43
  • 2
    @ADRENALIN Вы можете наследовать от первичного типа (возможно, dict), если все значения атрибута класса являются сериализуемыми, и вы не против взлома. Вы также можете использовать jsonpickle или json_tricks или что-то вместо стандартного (по-прежнему настраиваемый кодер, но не тот, который вам нужно написать или вызвать). Первый распиливает экземпляр, последний сохраняет его как атрибут атрибутов, который вы можете изменить, реализуя __json__encode__ / __json_decode__ (раскрытие: я сделал последний). – Mark 20 October 2016 в 13:02
import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)
3
ответ дан rectangletangle 22 August 2018 в 08:53
поделиться
  • 1
    Из doc : Параметр default(obj) - это функция, которая должна возвращать сериализуемую версию obj или поднять TypeError. По умолчанию default просто вызывает TypeError. – luckydonald 28 June 2016 в 16:09

json ограничено в терминах объектов, которые он может печатать, а jsonpickle (возможно, вам нужен pip install jsonpickle) ограничен в терминах, он не может отступать от текста. Если вы хотите проверить содержимое объекта, класс которого вы не можете изменить, я все равно не мог найти более строгий путь:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

Обратите внимание, что они все еще не могут распечатать объект методы.

4
ответ дан ribamar 22 August 2018 в 08:53
поделиться

Просто добавьте метод to_json в ваш класс следующим образом:

def to_json(self):
  return self.message # or how you want it to be serialized

И добавьте этот код (из этот ответ ) , чтобы где-то в верхней части всего:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

Это будет модуль monkey-patch json, когда он будет импортирован, поэтому JSONEncoder.default () автоматически проверяет специальный метод «to_json ()» и использует его для кодирования объект, если найден.

Так же, как сказал Онур, но на этот раз вам не нужно обновлять каждый json.dumps() в вашем проекте.

14
ответ дан Samuel Liew 22 August 2018 в 08:53
поделиться
  • 1
    Большое спасибо! Это единственный ответ, который позволяет мне делать то, что я хочу: иметь возможность сериализовать объект без изменения существующего кода. Другие методы в основном не работают для меня. Объект определен в сторонней библиотеке, а код сериализации также является сторонним. Изменение их будет неудобно. С помощью вашего метода мне нужно сделать только TheObject.to_json = my_serializer. – Yongwei Wu 11 October 2017 в 13:12

Я столкнулся с этой проблемой, когда попытался сохранить модель Peewee в PostgreSQL JSONField.

После долгой работы, вот общее решение.

Ключ к моему решение проходит через исходный код Python и понимает, что документация по коду (описанная здесь здесь ) уже объясняет, как расширить существующий json.dumps для поддержки других типов данных.

Предположим, иметь модель, которая содержит некоторые поля, которые не могут быть сериализованы для JSON, и модель, которая содержит поле JSON, первоначально выглядит следующим образом:

class SomeClass(Model):
    json_field = JSONField()

Просто определите пользовательский JSONEncoder, как это:

class CustomJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
            return < whatever value you want >
        return json.JSONEncoder.default(self, obj)

    @staticmethod
    def json_dumper(obj):
        return json.dumps(obj, cls=CustomJsonEncoder)

А затем просто используйте его в своем JSONField, как показано ниже:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

Ключом является метод default(self, obj) выше. Для каждой жалобы ... is not JSON serializable, которую вы получаете от Python, просто добавьте код для обработки типа unserializable-to-JSON (например, Enum или datetime)

Например, вот как я поддерживаю класс, наследующий от Enum:

class TransactionType(Enum):
   CURRENT = 1
   STACKED = 2

   def default(self, obj):
       if isinstance(obj, TransactionType):
           return obj.value
       return json.JSONEncoder.default(self, obj)

Наконец, с помощью кода, реализованного, как описано выше, вы можете просто преобразовать любые модели Peewee в объект JSON-seriazable, как показано ниже:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:

  1. Он применим к другим ORM (Django и т. д.) вообще
  2. . Кроме того, если вы понимаете, как работает json.dumps, это решение также работает с Python (без ORM) вообще

. Все вопросы, пожалуйста, публикуйте в разделе комментариев. Спасибо!

0
ответ дан sivabudh 22 August 2018 в 08:53
поделиться

Это небольшая библиотека, которая сериализует объект со всеми его дочерними элементами в JSON, а также анализирует его обратно:

https://github.com/Toubs/PyJSONSerialization/

1
ответ дан Tobi 22 August 2018 в 08:53
поделиться

На днях я столкнулся с этой проблемой и реализовал более общую версию Encoder для объектов Python, которая может обрабатывать вложенные объекты и наследуемые поля:

import json
import inspect

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

Пример:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}

class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y

    def f(self):
        print "f"

class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()

print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

Результат:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}
20
ответ дан tobigue 22 August 2018 в 08:53
поделиться
  • 1
    Работайте отлично. Благодарю. – Doo Dah 24 February 2016 в 19:39
  • 2
    Хотя это немного устарело. Я сталкиваюсь с некоторой ошибкой в ​​круговом импорте. Поэтому вместо return obj в последней строке я сделал это return super(ObjectEncoder, self).default(obj). Ссылка ЗДЕСЬ – Thulasi Ram 11 April 2017 в 13:44
8
ответ дан tryer3000 22 August 2018 в 08:53
поделиться

Мне понравился метод Lost Koder. Я столкнулся с проблемами при попытке сериализации более сложных объектов, чьи члены / методы не сериализуемы. Вот моя реализация, которая работает с большим количеством объектов:

class Serializer(object):
    @staticmethod
    def serialize(obj):
        def check(o):
            for k, v in o.__dict__.items():
                try:
                    _ = json.dumps(v)
                    o.__dict__[k] = v
                except TypeError:
                    o.__dict__[k] = str(v)
            return o
        return json.dumps(check(obj).__dict__, indent=2)
0
ответ дан Will Charlton 22 August 2018 в 08:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: