You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django与Shell写入SQL时JSONField结果不一致问题排查

Django JSONField 存储异常问题解答

问题描述

自定义模型代码

class myJSONField(models.JSONField):
    def get_prep_value(self, v):
        if v is None:
            return value
        return json.dumps(v, ensure_ascii = False)

class Product(models.Model):
    data                = myJSONField()
    number              = models.PositiveIntegerField()

测试对比

  1. Django ORM写入结果:
    执行Product.create(number = 1, data = {"direction": "süd"})后,数据库存储内容为:

    "{\"direction\": \"s\u00fcd\"}"
    
  2. SQLite直接写入结果:
    执行以下代码:

    conn = sqlite3.connect('db.sqlite3')
    c = conn.cursor()
    test = json.dumps({"direction": "Süd"}, ensure_ascii = False)
    sql = ("""UPDATE test_product SET data = ? WHERE id=1""")
    c.execute(sql, [test])
    conn.commit()
    

    数据库存储内容为:

    {"direction": "süd"}
    

补充测试细节

  • SQLite中省略ensure_ascii=False时,存储结果为{"direction": "s\u00fcd"}(无外层引号);
  • Django写入后,用sqlite3直接读取得到[(1, 1, '"{\"direction\": \"s\u00fcd\"}"')],但通过Django ORM读取能正确解析为{'direction': 'süd'}。

疑问

  1. 为何Django逻辑会忽略ensure_ascii=False参数?
  2. 如何让JSONField存储正确的JSON(无转义引号)?

问题解答

1. ensure_ascii=False被忽略的原因

自定义myJSONField的get_prep_value方法触发了双重序列化:

  • 你手动调用json.dumps生成了JSON字符串;
  • Django原生JSONField会将你返回的字符串当作普通Python对象,再次执行JSON序列化,最终给整个字符串加上外层引号,并转义内部引号。
    另外代码存在bug:if v is None: return value中的value未定义,应改为return None。

2. 正确存储无转义JSON的方法

无需手动重写序列化逻辑,利用Django原生参数配置即可:

方法一:直接给原生JSONField传参数(Django 3.1+)

from django.db import models

class Product(models.Model):
    data = models.JSONField(ensure_ascii=False)
    number = models.PositiveIntegerField()

方法二:自定义JSON编码器(兼容低版本)

from django.db import models
import json

class UnicodeJSONEncoder(json.JSONEncoder):
    def __init__(self, **kwargs):
        kwargs.setdefault('ensure_ascii', False)
        super().__init__(**kwargs)

class Product(models.Model):
    data = models.JSONField(encoder=UnicodeJSONEncoder)
    number = models.PositiveIntegerField()

方法三:全局配置序列化规则

在项目settings.py中添加:

import json
from django.core.serializers.json import DjangoJSONEncoder

class CustomJSONEncoder(DjangoJSONEncoder):
    def __init__(self, **kwargs):
        kwargs.setdefault('ensure_ascii', False)
        super().__init__(**kwargs)

JSON_ENCODER = 'your_project_name.settings.CustomJSONEncoder'

核心原则:不要手动调用json.dumps导致双重序列化,依赖Django原生JSONField的序列化逻辑,通过参数或编码器控制ensure_ascii即可得到正确的无转义JSON存储结果。


内容的提问来源于stack exchange,提问作者xtlc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:37:37