【老生常谈】Django 中 JSON 化 queryset 和 model

Django 里对 queryset 和 model 的序列化真的是一个老生常谈的问题。对于 queryset,我们一般用 django 内置的 serialize,但是它有一个缺点,就是不能对 model 实例进行序列化。这时候就需要我们手动进行调整。

一、思路。 

我们需要自定义一个序列化函数,但是这个函数不能只单单满足 querySet 或者 model,我们应该把它变成一个更加通用的方法。这里我们直接用到了 json 类,这是最基本的序列化类,它支持自定义序列化规则,我们可以根据序列化对象的不同来应用不同的规则。

二、实现

# coding=utf-8
import json
from django.db import models
from django.core.serializers import serialize
from django.db.models.query import QuerySet


class JSONEncoder(json.JSONEncoder):
    """ 继承自simplejson的编码基类,用于处理复杂类型的编码
    """

    def default(self, obj):
        if isinstance(obj, QuerySet):
            """ Queryset实例
            直接使用Django内置的序列化工具进行序列化
            但是如果直接返回serialize('json',obj)
            则在simplejson序列化时会被从当成字符串处理
            则会多出前后的双引号
            因此这里先获得序列化后的对象
            然后再用simplejson反序列化一次
            得到一个标准的字典(dict)对象
            """
            return json.loads(serialize('json', obj))
        if isinstance(obj, models.Model):
            """
            如果传入的是单个对象,区别于QuerySet的就是
            Django不支持序列化单个对象
            因此,首先用单个对象来构造一个只有一个对象的数组
            这是就可以看做是QuerySet对象
            然后此时再用Django来进行序列化
            就如同处理QuerySet一样
            但是由于序列化QuerySet会被'[]'所包围
            因此使用string[1:-1]来去除
            由于序列化QuerySet而带入的'[]'
            """
            return json.loads(serialize('json', [obj])[1:-1])
        if hasattr(obj, 'isoformat'):
            # 处理日期类型
            return obj.isoformat()
        return json.JSONEncoder.default(self, obj)

使用方法:

json.dumps(result, cls=JSONEncoder)