Python 将类的对象转换成 JSON 详解

JSON这个东西相信现在大家都已经不再陌生,第一次接触它时我便对它爱不释手!记得在发现 JSON 之间,一直使用 XML 结构来传递数据,但 XML 这个东西太麻烦了,不管是在服务端或是 JS 里面,写入与读入都是哪么的麻烦。而 JSON 实在是太方便了,通过一些开源的JSON 类库可以很方便的将一个对象转换成字符串的形式来传递。
网上也有很多讲Python + JSON 的文章,但我这里要讲的是它们都没有提到的一种常用的方式。
 
昨晚在用Python + Django 做 AJAX 的东西,我自定义了一个返回值对象 (ExecuteState) 的类,再用 JSON 的方式返回到页面前端。
以前在.NET 里面做类似的操作一直是在用一个叫 Json.NET 的开源类库,很方便。于是在 Python 里面我继续用这种方式,而 Django 里面也有自带一个叫 simplejson 的类。
开始想想实现这东西应该很简单,可没想到后面因为一个很小的细节让我绕了一大圈…在此写出来与大家分享,以免再次走弯路。

例子

Python 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from django.utils import simplejson
# 其它 django 的引用这里省略

class ExecuteState():
    """
    summary:
        返回值对象,用于返回执行状态
    """
    # 是否执行成功,默认是 True 成功,因为经过长期使用发现 True 用得较多
    success = True
    # 提示消息
    message = ""
    # 导致不成功的标志,错误是由谁引起的
    mark = ""
    # 导致不成功的对象 [object 类型]
    owner = None

    def json(self):
        """
        summary:
            得到本对象的 JSON 格式的字符串
        """
        return simplejson.encode(str(obj2dict(self)))

def obj2dict(obj):
    """
    summary:
        将 object 转换成 dict 类型
    """
    memberlist = [m for m in dir(obj)]
    _dict = {}
    for m in memberlist:
        if m[0] != "_" and not callable(m):
            _dict[m] = getattr(obj,m)

    return _dict

def signup(request):
    """
    summary:
        signup 视图,URLs 里面的定义这里省略
    """
    state = ExecuteState()

    if reuqest.POST:
        # 提交视图处理
        username = request.POST["username"]
        realname = request.POST["realname"]
        password = request.POST["password"]
        password_confirm = request.POST["password_confirm"]
        email = request.POST["email"]

        # 重点!验证输入的内容是否符合要求
        state.success = False

        if len(username) < 4 or len(username) > 16:
            state.message = "用户名太短,要求 4-16 个字符。"
            state.mark = "username"
            # 不符合要求了,在这直接用 return 中断并返回 state 用 simplejson.encode 将 state 转换成 JSON
            # 注意!这里有用 dir(state) 这个就是我要讲的一个细节
            #
            return state.json()

        if not regex_check_chinese(realname):
            state.message = "姓名要求必须是中文。"
            state.mark = "realname"
            return state.json()

        # 后面的提交数据库省略...

        # 成功消息
        state.success = True
        state.message = "注册成功。"
        return state
    else:
        # signup 地址普通打开的处理

Javascript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
    这里以 jQuery 的 Ajax 实现为例
    引用、调用提交事件 这里略...
 */
/**
 * 注册页面 JS 类库
 */
var Signup = {
    /**
     * Ajax 提交事件
     */
    post : function(){
        // 读 DOM 的值略...

        $.ajax({
            url : "/signup",
            data: "username=" + username + "&password=" + password,
            dataType: "json",
            type : "post",
            success : function(state){
                /*
                    在 JS 里面接收 state,jQuery 的 AJAX 会自动将它用 JSON 反序列化成对象
                    于是我们就可以像在 Python 里面一样使用了 如 state.message
                */
                if(! state.success){
                    # 错误处理
                    alert(state.message);
                }
                else{
                    alert("注册成功。");
                    location.href = "/success.html";
                }
            }
        })
    }
}

现在整个就完成了,里面一些不重要代码的实现没有写,这个别拿去运行哦,不能通过的。
我这里只是写出实现的方式,当然里面的 ExecuteState obj2dict 这两个东西是完整的,可以直接拿来使用。

附注:本文中的代码着色来自于 http://pastie.org/

另外,Blogbus 发文章怎么有字数限制呀?像我经常会发格式化后的 HTML 代码,这样贴出来的代码有高亮着色,我看了一下 HTML,居然是 20000 个限制。晕!第一次遇到有字数限制的博客…不让发那么多我偏要发,限制…破解之!