如何更高效更新Django JSONField存储的列表内的指定元素
解决方案
下面分两种场景给出更简便的实现方式:
1. 应用层Python优化写法
你原来的逻辑是对的,利用name全局唯一的特性,可以先把列表转为以name为键的字典做更新,代码可读性和可维护性更高,批量更新时效率优势更明显:
obj = MyModel.objects.get(pk=1) # 转换为 {name: 字段配置} 的字典结构 data_map = {item["name"]: item for item in obj.json_data} new_data = {"name": "field2", "value": "99", "type":"number"} # 直接覆盖对应name的配置,不存在就自动新增 data_map[new_data["name"]] = new_data # 转回列表后保存 obj.json_data = list(data_map.values()) obj.save()
这种写法的时间复杂度和你原来的列表推导方式一致,都是O(n),但如果需要同时更新多个字段,只需要往data_map里多次赋值即可,不需要多次遍历原列表。
2. 数据库层直接更新(更高性能)
如果你用的是PostgreSQL的JSONB类型(Django自带的django.contrib.postgres.fields.JSONField默认存储为JSONB),可以直接用PostgreSQL的JSON路径查询在数据库层面完成更新,不需要把整个JSON数据拉取到应用层,数据量大的时候性能优势非常显著:
from django.db.models import F, Value from django.db.models.expressions import Func new_data = {"name": "field2", "value": "99", "type":"number"} target_name = new_data["name"] MyModel.objects.filter(pk=1).update( # 先过滤掉所有name匹配的旧元素,再追加新元素,一步完成更新 json_data = Func( F("json_data"), Value(f'[*] ? (@.name != "{target_name}")'), function="jsonb_path_query_array", ) + Value([new_data]) )
这个写法同时支持更新已有元素、新增不存在的元素,不需要额外判断逻辑。
内容的提问来源于stack exchange,提问作者Kevin Ramirez Zavalza
相关产品推荐
相关产品推荐

