如何使python对象json序列化?

Posted

技术标签:

【中文标题】如何使python对象json序列化?【英文标题】:How to make a python object json-serialized? 【发布时间】:2019-07-23 01:57:15 【问题描述】:

我想serialize a python object,在将它保存到mysql(基于Django ORM)后,我想获取它并将这个对象传递给需要这种对象作为参数的函数。

以下两部分是我的主要逻辑代码:

1 保存参数部分:



class Param(object):
    def __init__(self, name=None, targeting=None, start_time=None, end_time=None):
        self.name = name
        self.targeting = targeting
        self.start_time = start_time
        self.end_time = end_time
    #...

param = Param()
param.name = "name1"
param.targeting= "targeting1"


task_param = 
            "task_id":task_id,              # string
            "user_name":user_name,          # string
            "param":param,                  # Param object
            "save_param":save_param_dict,   # dictionary
            "access_token":access_token,    # string
            "account_id": account_id,       # string
            "page_id": page_id,             # string
            "task_name":"sync_create_ad"    # string
        


class SyncTaskList(models.Model):
    task_id = models.CharField(max_length=128, blank=True, null=True)
    ad_name = models.CharField(max_length=128, blank=True, null=True)
    user_name = models.CharField(max_length=128, blank=True, null=True)
    task_status = models.SmallIntegerField(blank=True, null=True)
    task_fail_reason = models.CharField(max_length=255, blank=True, null=True)
    task_name = models.CharField(max_length=128, blank=True, null=True)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField(blank=True, null=True)
    task_param = models.TextField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'sync_task_list'



SyncTaskList(
                task_id=task_id,
                ad_name=param.name,
                user_name=user_name,
                task_status=0,
                task_param = task_param,
            ).save()

2 使用参数部分


def add_param(param, access_token):
    pass

task_list = SyncTaskList.objects.filter(task_status=0)
for task in task_list:
    task_param = json.loads(task.task_param)
    add_param(task_param["param"], task_param["access_token"]) # pass param object to function add_param

如果我直接使用Django ORM 将task_param 保存到mysql 会报错,

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

在 ORM 操作之后,我得到字符串谁的属性名称用单引号括起来,例如:


# in mysql it saved as 

 task_param: " task_param: 'task_id': 'e4b8b240cefaf58fa9fa5a591221c90a',
              'user_name': 'jimmy',
              'param': Param(name='name1',
                                    targeting='geo_locations',
                                   ),
              'save_param': "

我现在对序列化python对象感到困惑,那么如何加载这个原始对象并将其传递给函数?

非常欢迎任何评论。非常感谢。

到目前为止更新我的解决方案

task_param = 
            # ...
            "param":vars(param),            # turn Param object to dictionary 
            # ...
            

SyncTaskList(
                #...
                task_param = json.dumps(task_param),
                #...
            ).save()

#task_list = SyncTaskList.objects.filter(task_status=0)
#for task in task_list:
    task_param = json.loads(task.task_param)
    add_param(Param(**task_param["param"]), task_param["access_token"])

根据@AJS 的回答更新

直接pickle dumps并保存为binary field,然后pickle loads也可以使用

对此有更好的解决方案吗?

【问题讨论】:

如果我在 MySql 中正确理解它,您将 task_param 保存为字符串,在 task_param 列下,并且您使用单引号保存它。如果我错了,请纠正我 使用json.dumps(obj)obj 转换为JSON。 @KlausD。它会引发错误TypeError: Object of type 'Param' is not JSON serializable @AJS 是的,如果我像上面的代码所示直接保存它,它会自动变成单引号样式 obj 必须是一个简单的 Python 结构,由字典、列表、字符串、数字等内置类型组成...您的 param 键不是。 【参考方案1】:

尝试查看 msgpack https://msgpack.org/index.html

不像pickle,它是python特有的,msgpack被许多语言支持(所以你用来写mysql的语言可以不同于用来读的语言)。

还有一些项目将这些序列化程序库集成到 Django 模型字段中:

泡菜:https://pypi.org/project/django-picklefield/ 消息包:https://github.com/vakorol/django-msgpackfield/blob/master/msgpackfield/msgpackfield.py

【讨论】:

【参考方案2】:

您可以使用pickle 基本上您正在序列化您的python 对象并将其保存为MySQL 数据库中的字节,使用BinaryField 作为您在Django 中的模型字段类型,因为我认为JSON 序列化不适用于您的情况因为您的 dict 中也有一个 python 对象作为值,所以当您从 db 中获取数据时,只需 unpickle 它的语法类似于 json 库,请参见下文。

import pickle
#to pickle
data = pickle.dumps('name':'testname')
# to unpickle just do
pickle.loads(data)

所以在你的情况下,当你解开你的对象时,你应该以与你做泡菜之前相同的形式获取数据。

希望这会有所帮助。

【讨论】:

感谢您的回复,pickle.dump 之后我可以得到一个字节数据,但是当它被Django ORM 保存到 mysql 时,它变成了一个字符串,我不能再加载它了跨度> 使用pickle.dumps应该是字符串,你错过了s

以上是关于如何使python对象json序列化?的主要内容,如果未能解决你的问题,请参考以下文章

python模块之序列化

python 序列号模块

序列化特定类型时如何使 JSON.Net 序列化程序调用 ToString()?

如何实现一个优雅的Python的Json序列化库

使用常规编码器使对象 JSON 可序列化

Python学习日记(十八) 序列化模块