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()
测试对比
Django ORM写入结果:
执行Product.create(number = 1, data = {"direction": "süd"})后,数据库存储内容为:"{\"direction\": \"s\u00fcd\"}"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'}。
疑问
- 为何Django逻辑会忽略
ensure_ascii=False参数? - 如何让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
相关产品推荐
相关产品推荐

