json dumps 不要空格

json.dumps((separators=(',', ': '))


效果就是:

args = {
    "frms_ware_category": "1002",
    "user_info_mercht_userno": "558f647c20058915ffa8544f",
    "user_info_mercht_userlogin": "zhangsan",
    "user_info_dt_register": datetime(2016, 3, 3, 3, 3, 3).strftime("%Y%m%d%H%M%S"),
    "user_info_register_ip": "11.11.11.11",
    "user_info_status": "1",
    "user_info_last_time": "0",
    "user_info_bind_ido": "1",
    "user_info_history_time": "0",
    "user_info_history_amount": "0"
}

json.dumps(args, separators=(',', ':'))


最后的结果是:

'{"user_info_history_time":"0","user_info_last_time":"0","user_info_bind_ido":"1","user_info_mercht_userno":"558f647c20058915ffa8544f","user_info_status":"1","user_info_dt_register":"20160303030303","user_info_register_ip":"11.11.11.11","user_info_history_amount":"0","frms_ware_category":"1002","user_info_mercht_userlogin":"zhangsan"}'


json dumps 按 keys 排序

json.dumps(args, sort_keys=True)


实践效果:

print (json.dumps(args, indent=4, sort_keys=True))


结果输出:

{
    "frms_ware_category": "1002", 
    "user_info_bind_ido": "1", 
    "user_info_dt_register": "20160303030303", 
    "user_info_history_amount": "0", 
    "user_info_history_time": "0", 
    "user_info_last_time": "0", 
    "user_info_mercht_userlogin": "zhangsan", 
    "user_info_mercht_userno": "558f647c20058915ffa8544f", 
    "user_info_register_ip": "11.11.11.11", 
    "user_info_status": "1"
}


json 序列化 datetime

今天尝试一个例子, 在过程中发现了一个问题,这里简单得给出一个问题发生的现场:

import json
from datetime import datetime, timedelta

data = {
    "username": "tyrael",
    "registe_at": datetime.now() - timedelta(days=365*6)
}
json.dumps(data)


然后,如果你尝试一下这个例子,你会发现会抛出类似的异常,其关键问题是:

TypeError: datetime.datetime(2010, 4, 6, 19, 27, 49, 747551) is not JSON serializable


其实就是说 json 无法序列化 datetime 的时间类型。

查阅一下 json 模块的官方说明文档,然后再结合一下 google,发现了两个解决方案,其中一个是指定 cls 参数,另外一个是指定 default 参数,下面分别就这两个方法来写个示例。

cls 参数

import json
from json import JSONDecoder, JSONEncoder
from datetime import datetime, timedelta

data = {
    "username": "tyrael",
    "registe_at": datetime.now() - timedelta(days=365*6)
}


class DateTimeDecoder(json.JSONDecoder):
    FORMAT = "%Y-%m-%d %H:%M:%S"

    def __init__(self, *args, **kargs):
        JSONDecoder.__init__(self, object_hook=self.dict_to_object,
                             *args, **kargs)

    def dict_to_object(self, d): 
        for k, v in d.iteritems():
            try:
                dateobj = datetime.strptime(v, self.FORMAT)
                d[k] = dateobj
            except:
                pass
        return d

class DateTimeEncoder(JSONEncoder):
    """ Instead of letting the default encoder convert datetime to string,
        convert datetime objects into a dict, which can be decoded by the
        DateTimeDecoder
    """
    FORMAT = "%Y-%m-%d %H:%M:%S"

    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime(self.FORMAT)
        else:
            return JSONEncoder.default(self, obj)


然后是测试的代码:

>>> json.loads('{"username": "tyrael", "registe_at": "2010-04-06 19:27:49"}', cls=DateTimeDecoder)
{u'registe_at': datetime.datetime(2010, 4, 6, 19, 27, 49),
 u'username': u'tyrael'}

>>> json.dumps(data, cls=DateTimeEncoder)
'{"username": "tyrael", "registe_at": "2010-04-06 19:27:49"}'


default 参数

def date_default(obj):
    if isinstance(obj, datetime):
        return obj.strftime("%Y-%m-%d %H:%M:%S")
    else:
        return JSONEncoder.default(self, obj)
json.dumps(data, default=date_default)

def date_default(pairs):
rtn = {}
for key_value in pairs:
    k, v = key_value
    try:
        dateobj = datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
        rtn[k] = dateobj
    except:
        rtn[k] = v
return rtn

json.loads('{"username": "tyrael", "registe_at": "2010-04-06 19:27:49"}', object_pairs_hook=date_default)


其实两种方式的本质都是指定一下转换规则,也就是指定一下转换器。没有太大的技术难度。