【问题标题】:Creating UTF-8 JsonResponse in Django在 Django 中创建 UTF-8 JsonResponse
【发布时间】:2016-04-20 07:36:33
【问题描述】:

是否有任何简单的方法可以覆盖DjangoJSONEncoder.ensure_ascii 并将其设置为False 或以任何其他方式在django.http.JsonResponse 中输出非ascii 文本?

【问题讨论】:

    标签: json django utf-8


    【解决方案1】:

    我没有找到比使用已经安装的 REST 框架更好的方法:

    from rest_framework.decorators import api_view, permission_classes
    from rest_framework.permissions import IsAuthenticatedOrReadOnly
    from rest_framework.response import Response
    
    from .models import INITIATOR_TYPES
    
    @api_view(['GET'])
    @permission_classes((IsAuthenticatedOrReadOnly, ))
    def initiator_types(request):
        data = {t[0]: str(t[1]) for t in INITIATOR_TYPES}
        return Response(data)
    

    但我真的不喜欢它。比JsonResponse复杂多了:https://stackoverflow.com/a/24411716/854477

    【讨论】:

    • 您应该将其作为原始问题的一部分。
    • 这是我决定分享的解决方案,同时尝试寻找更好的解决方案。
    【解决方案2】:

    编辑:

    或者,如果您倾向于 utf-8 格式,请使用 Django 的 JsonResponse() 代替:

    return HttpResponse(json.dumps(response_data, ensure_ascii=False),
             content_type="application/json")
    

    return JsonResponse(json.dumps(response_data, ensure_ascii=False), safe=False)
    

    更多关于safe=FalseHERE


    旧:

    您无需进行任何更改。

    虽然 Django 以 ASCII(来自 UTF-8)创建 JSON 数据,但 Javascript 会自动将其解码回 UTF-8。

    【讨论】:

    • 感谢您的建议,但我更喜欢可读性,而不是稍微更好的向后兼容性,在我的情况下我根本不需要。此外,在 RFC 7159 中推荐使用 UTF-8。
    • JsonResponse(json.dumps(response_data, ensure_ascii=False), ...) 不起作用,因为这会对数据进行双重编码。在那种情况下设置safe=False 没有意义either,因为该标志适用于将数据编码为 JSON 时接受的内容。由于您已经将所有对象编码为 JSON 字符串,因此不再需要编码“不安全”对象。
    【解决方案3】:
    from django.core.serializers.json import DjangoJSONEncoder
    from django.http import JsonResponse
    
    
    class MyJsonResponse(JsonResponse):
        def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, **kwargs):
            json_dumps_params = dict(ensure_ascii=False)
            super().__init__(data, encoder, safe, json_dumps_params, **kwargs)
    

    【讨论】:

    • 这可以通过允许 json_dumps_params 被覆盖来改进。
    【解决方案4】:

    从 Django 1.9 开始,您可以配置 JSONResponse 以禁用 ensure_ascii 开关,方法是传入 json_dumps_params argument 的值:

    return JsonResponse(response_data, safe=False, json_dumps_params={'ensure_ascii': False})
    

    使用ensure_ascii=Falsejson.dumps() 为非 ASCII 码点输出 UTF-8 数据。

    除非设置不同,否则您可以继承 JsonResponse 以使其成为默认值:

    from django.http.response import JsonResponse
    
    class UTF8JsonResponse(JsonResponse):
        def __init__(self, *args, json_dumps_params=None, **kwargs):
            json_dumps_params = {"ensure_ascii": False, **(json_dumps_params or {})}
            super().__init__(*args, json_dumps_params=json_dumps_params, **kwargs)
    

    然后在整个过程中使用它而不是 JsonResponse。

    在极端情况下,您可以对课程进行猴子补丁以将ensure_ascii 默认设置为False;将以下内容放入 Django 应用程序的合适模块中(例如,在名为 patches.py 的文件中):

    import logging
    from functools import wraps
    from django.http.response import JsonResponse
    
    logger = logging.getLogger(__name__)
    
    def patch_jsonresponse_disable_ensure_ascii():
        if getattr(JsonResponse, '_utf8_patched', False):
            # Already patched. Add warning in logs with stack to see what location
            # is trying to patch this a second time.
            logger.warning("JSONResponse UTF8 patch already applied", stack_info=True)
            return
    
        logger.debug("Patching JSONResponse to disable ensure_ascii")
        orig_init = JsonResponse.__init__
    
        @wraps(orig_init)
        def utf8_init(self, *args, json_dumps_params=None, **kwargs):
            json_dumps_params = {"ensure_ascii": False, **(json_dumps_params or {})}
            orig_init(self, *args, json_dumps_params=json_dumps_params, **kwargs)
    
        JsonResponse.__init__ = utf8_init
        JsonResponse._utf8_patched = True  # to prevent accidental re-patching
    

    然后将patch_jsonresponse_disable_ensure_ascii 导入到您的 Django 设置文件中,并根据您所需的配置调用它:

    from yourapp.patches import patch_jsonresponse_disable_ensure_ascii
    
    JSON_RESPONSES_UTF8 = True
    
    if JSON_RESPONSES_UTF8:
        patch_jsonresponse_disable_ensure_ascii()
    

    【讨论】:

    • 是否有任何设置项将其设置为 False golbally 而不是将其放入每个 JsonResponse 中?
    • @Jcyrss:扩展了我的答案,为您提供更多层次,包括猴子补丁 Django 本身始终将标志设置为 false。
    猜你喜欢
    • 2017-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    相关资源
    最近更新 更多