使用 Django 添加额外的 \\ 字符的 JSON 编码

Bri*_*her 2 python django json django-models

我正在尝试创建一个函数,它将包含一条消息和一个 Django 模型实例的字典转换为 JSON,我可以将其传递回客户端。例如,我在models.py 中定义了模型Test。

from django.db import models

class Test(models.Model):
    test_field = models.CharField(max_length=40)
Run Code Online (Sandbox Code Playgroud)

我已经根据这个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)
Run Code Online (Sandbox Code Playgroud)

然后我开始创建一个实例以及一条状态消息:

t = Test(test_field="hello")
d = {"entry": t, "message": "Congratulations"}
json = dumps(d)
Run Code Online (Sandbox Code Playgroud)

json的内容是:

{"entry": "{\\"pk\\": null, \\"model\\": \\"hours.test\\", \\"fields\\": {\\"test_field\\": \\"hello\\"}", "message": "Congratulations"}
Run Code Online (Sandbox Code Playgroud)

这基本上是我想要的,除了所有额外的 \\字符。为什么将这些插入到 json 中?如何修改我的 DjangoJSONEncoder 使其不插入 \ 字符?

笔记

如果我只是手动编码模型实例,我不会得到所有额外的\\字符。

s = serialize('json', [t])
s[1:len(s)-2]
Run Code Online (Sandbox Code Playgroud)

这输出:

{"pk": null, "model": "hours.test", "fields": {"test_field": "hello"}
Run Code Online (Sandbox Code Playgroud)

编辑

根据 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)
Run Code Online (Sandbox Code Playgroud)

Dan*_*man 5

不幸的是,你的逻辑是错误的。正如您所说,您的“最简单的方法”返回一个字符串-但此时您不需要字符串,而是需要字典。您最终会在字符串中序列化一个字符串,因此需要转义额外的引号。

幸运的是,该serialize函数的格式选项之一是python- 将查询集“序列化”为 Python 字典。所以你只需要:

return serialize('python', obj))
Run Code Online (Sandbox Code Playgroud)