Django的save()函数是否覆盖数据库旧数据及写入重复问题处理
问题根因分析
你遇到的旧数据被覆盖问题核心是模型字段定义存在逻辑冲突:
- 你将
TRAN_TYPE设为了单字段主键,Django的save()默认逻辑为:如果模型实例的主键字段有值,就执行UPDATE操作更新对应主键的已有记录,只有主键为空时才会执行INSERT新增记录。哪怕你设置了TIME_UPDATED+TRAN_TYPE的联合唯一约束,也会被单字段主键的判断逻辑覆盖,因此只要TRAN_TYPE相同,不管时间如何变化,都会覆盖旧记录。 - 你设置的联合唯一约束和单主键定义本身是矛盾的:主键已经保证
TRAN_TYPE全局唯一,联合唯一约束完全不会生效。
修复方案
第一步:调整模型字段定义
删除TRAN_TYPE的主键声明,新增独立的自增主键,保留联合唯一约束即可,修改后的模型如下:
class Transactions(models.Model): # 新增自增ID作为主键,也可以省略该行,Django默认会自动创建id主键字段 id = models.AutoField(primary_key=True) class Meta: db_table='TRANSACTIONS' unique_together=(("TIME_UPDATED","TRAN_TYPE",),) indexes=[ models.Index(fields=["TIME_UPDATED","TRAN_TYPE"]), models.Index(fields=["TRAN_TYPE"]) ] TIME_UPDATED = models.DateTimeField() # 删除此处的primary_key=True参数 TRAN_TYPE = models.CharField(max_length=32) SUCCESS = models.IntegerField() TECHNICAL_DECLINES = models.IntegerField() BUSINESS_DECLINES = models.IntegerField() TOTAL = models.IntegerField() PERCENTAGE_TECH_DEC = models.FloatField() def __str__(self): return self.TRAN_TYPE # 补充args和kwargs参数传递,避免后续调用save时报错 def save(self,D,tran, *args, **kwargs): self.TIME_UPDATED=D self.TRAN_TYPE=T=tran['Type'] self.SUCCESS=S=int(tran['Success']) self.TECHNICAL_DECLINES=TD=int(tran['Tech_dec']) self.BUSINESS_DECLINES=BD=int(tran['Bus_dec']) self.TOTAL=total=S+TD+BD if total==0:# 避免除零报错 self.PERCENTAGE_TECH_DEC=0 else: self.PERCENTAGE_TECH_DEC=((TD/(total))*100) super(Transactions,self).save(*args, **kwargs)
第二步:更新数据库表结构
修改完模型后执行makemigrations和migrate命令同步表结构,操作前请先备份存量数据避免丢失。
第三步:可选异常处理优化
如果需要避免重复插入相同时间+相同交易类型的记录,可以在调用save时添加force_insert=True参数强制走插入逻辑,一旦触发联合唯一约束会抛出IntegrityError,你可以捕获该异常做对应处理:
# 调用示例 from django.db import IntegrityError try: tran_obj = Transactions() tran_obj.save(D=current_time, tran=raw_data, force_insert=True) except IntegrityError: # 重复数据处理逻辑,比如打日志、跳过该条记录 print(f"时间{current_time}的{raw_data['Type']}交易数据已存在,跳过插入")
调整完成后,相同交易类型、不同时间点的数据都会作为新记录插入,不会再覆盖旧数据,同时联合唯一约束会避免同一时间点重复插入相同交易类型的数据,符合你存储全量历史数据的需求。
内容的提问来源于stack exchange,提问作者Shankz
相关产品推荐
相关产品推荐

