【问题标题】:JSON Encoding with Django adding extra \\ characters使用 Django 添加额外的 \\ 字符的 JSON 编码
【发布时间】:2011-08-29 04:32:18
【问题描述】:

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

from django.db import models

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

我已经基于 stackoverflow question 定义了 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)

【问题讨论】:

    标签: python django json django-models


    【解决方案1】:

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

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

    return serialize('python', obj))
    

    【讨论】:

    • 啊,这很有帮助,并且解决了我将来可能会遇到的查询集问题,但是,我目前正在处理模型案例。使用您的建议,我将那里的代码更改为return serialize('python', [obj]),除了 json 中的输入字段现在是单个元素数组之外,它的效果很好。有没有一种简单的方法可以在不先将模型实例放入列表的情况下做到这一点?感谢您的帮助。
    • 如果没有将其列在列表中,不,您可能只需要serialize('python', [obj])[0]
    • 啊这么简单,就是没看到。感谢您的帮助。
    • 太棒了。帮了我很多!
    【解决方案2】:

    您将Test 模型对象序列化为JSON 字符串,然后d 中的entry 字段是正在序列化的字符串,而不是数据结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-30
      • 2014-11-06
      • 2021-06-22
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多