Django JSON编码添加多余的\\字符

2 投票
2 回答
2898 浏览
提问于 2025-04-16 17:59

我正在尝试创建一个函数,这个函数可以把一个包含消息和Django模型实例的字典转换成JSON格式,这样我就可以把它传回给客户端。例如,我在models.py中定义了一个叫Test的模型。

from django.db import models

class Test(models.Model):
    test_field = models.CharField(max_length=40)

我根据这个StackOverflow的问题,扩展了simplejson的JSONEncoder:

from django.core.serializers import serialize
from django.utils.simplejson import dumps, loads, JSONEncoder
from django.db.models.query import QuerySet
from django.db import models
from django.utils.functional import curry

class DjangoJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, QuerySet):
            # `default` must return a python serializable
            # structure, the easiest way is to load the JSON
            # string produced by `serialize` and return it
            return loads(serialize('json', obj))
        if isinstance(obj, models.Model):
            #do the same as above by making it a queryset first
            set_obj = [obj]
            set_str = serialize('json', set_obj)
            #eliminate brackets in the beginning and the end 
            str_obj = set_str[1:len(set_str)-2]
            return str_obj
        return JSONEncoder.default(self,obj)

# partial function, we can now use dumps(my_dict) instead
# of dumps(my_dict, cls=DjangoJSONEncoder)
dumps = curry(dumps, cls=DjangoJSONEncoder)

接着,我创建了这个扩展的实例,并加上一个状态消息:

t = Test(test_field="hello")
d = {"entry": t, "message": "Congratulations"}
json = dumps(d)

json的内容是:

{"entry": "{\\"pk\\": null, \\"model\\": \\"hours.test\\", \\"fields\\": {\\"test_field\\": \\"hello\\"}", "message": "Congratulations"}

这基本上就是我想要的,除了多出来的\\字符。为什么这些字符会被插入到json中?我该如何修改我的DjangoJSONEncoder,让它不插入这些\字符呢?

注意

如果我手动编码模型实例,就不会出现多余的\\字符。

s = serialize('json', [t])
s[1:len(s)-2]

这段代码的输出是:

{"pk": null, "model": "hours.test", "fields": {"test_field": "hello"}

编辑

根据Daniel Roseman和Leopd的建议,我把DjangoJSONEncoder类修改成了下面这样:

class DjangoJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, QuerySet):
            # `default` must return a python serializable
            # structure, the easiest way is to load the JSON
            # string produced by `serialize` and return it
            return loads(serialize('python', obj))
        if isinstance(obj, models.Model):
            #do the same as above by making it a list first
            return serialize('python', [obj])[0]
        return JSONEncoder.default(self,obj)

2 个回答

1

你正在把你的 Test 模型对象转换成一个 JSON 字符串,然后 d 里的 entry 字段就是这个字符串,而不是数据结构本身。

5

很遗憾,你的逻辑有点问题。你说的“最简单的方法”返回的是一个字符串,但在那个时候你其实想要的是一个字典。这样一来,你就把一个字符串放在了另一个字符串里面,所以才会出现需要转义的额外引号。

幸运的是,serialize 函数有一个格式选项是 python,这个选项可以把查询集“序列化”为一个 Python 字典。所以你只需要:

return serialize('python', obj))

撰写回答