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

如何用Django基础命令实现数据更新与新增?解决重复创建问题

解决Django update_or_create重复创建数据的问题

你遇到的问题核心是错误使用了update_or_create的参数结构,导致每次触发命令时,系统把rate也当作了匹配现有记录的条件,而不是仅用唯一标识字段去匹配、更新rate值。

问题原因

update_or_create的逻辑是:用第一个参数里的字段匹配现有记录,如果匹配到就更新defaults里的字段;如果匹配不到,就创建包含所有查询字段+defaults字段的新记录。

你的代码里把需要更新的rate也放到了查询条件里:

CoronaAge.objects.update_or_create(
    age=title['age'],
    rate=title['rate']  # 错误:把更新字段当成了查询条件
)

这样一来,只要接口返回的rate值有变化,或者首次创建后再次触发命令,系统会因为找不到同时匹配age和rate的记录,直接创建新数据,最终导致重复。

修正后的代码

正确的做法是把唯一标识字段(比如age、sex、condition)作为查询条件,将需要更新的rate放到defaults字典中:

from django.core.management.base import BaseCommand
import requests
from demo.models import CoronaAge, CoronaSex, CoronaComorbidity

class Command(BaseCommand):
    def handle(self, *args, **kwargs):
        url = 'https://api.the2019ncov.com/api/fatality-rate'
        r = requests.get(url)
        titles = r.json()
        print(titles)
        
        # 按年龄统计数据
        for title in titles.get('byAge', []):
            CoronaAge.objects.update_or_create(
                age=title['age'],  # 唯一匹配条件
                defaults={'rate': title['rate']}  # 需要更新的字段
            )
        
        # 按性别统计数据
        for title in titles.get('bySex', []):
            CoronaSex.objects.update_or_create(
                sex=title['sex'],
                defaults={'rate': title['rate']}
            )
        
        # 按基础病统计数据
        for title in titles.get('byComorbidity', []):
            CoronaComorbidity.objects.update_or_create(
                condition=title['preExistingCondition'],
                defaults={'rate': title['rate']}
            )

额外优化点

  • 用titles.get('byAge', [])替代titles['byAge'] or [],避免接口返回的键不存在时抛出KeyError,代码更健壮;
  • 移除了未使用的context变量,精简代码。

修改后,每次触发命令时:

  • 系统会先根据唯一标识字段查找现有记录;
  • 找到则更新rate字段,找不到则创建新记录,彻底解决重复数据问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 00:47:46