如何在Django中无单独唯一字段时防止数据行重复?
Django多字段组合防重复的简便实现
你完全不用写一堆冗余的if判断,Django原生就支持多字段组合唯一的约束,同时搭配get_or_create方法就能完美解决问题,分两步改:
第一步:给模型加组合唯一约束
这是数据库层面的保障,即使代码有疏漏,数据库也会拦截重复数据。
新版Django(2.2及以上,推荐)
修改models.py,在Item模型的Meta类里添加UniqueConstraint:
class Item(models.Model): model = models.TextField() number = models.DecimalField(max_digits=5, decimal_places=2) timestamp = models.DateTimeField(auto_now=False, auto_now_add=False) city = models.TextField() state = models.TextField() class Meta: constraints = [ models.UniqueConstraint( fields=['model', 'number', 'timestamp', 'city', 'state'], name='unique_item_combination' ) ]
旧版Django(2.2以下)
用unique_together(属于遗留语法,但仍可使用):
class Item(models.Model): model = models.TextField() number = models.DecimalField(max_digits=5, decimal_places=2) timestamp = models.DateTimeField(auto_now=False, auto_now_add=False) city = models.TextField() state = models.TextField() class Meta: unique_together = ('model', 'number', 'timestamp', 'city', 'state')
第二步:简化视图层逻辑
把原来复杂的if判断换成get_or_create方法,它会自动根据指定的字段组合查询,不存在就创建新对象,存在则直接返回已有对象,一步到位:
修改views.py:
def collect(request): # 请求API数据 response = requests.get('url') data = json.loads(response.text) # 遍历处理每条数据 for key in data: props = key['properties'] timestamp = dateparse.parse_datetime(props['data_hora_gmt']) # 自动处理重复:组合存在则跳过,不存在则创建 Item.objects.get_or_create( model=props['model'], number=props['number'], timestamp=timestamp, city=props['city'], state=props['state'] ) return HttpResponseRedirect(reverse("index"))
补充说明
你原来的视图逻辑是错误的:它只是分别检查单个字段是否存在,而非字段组合是否存在,根本起不到防重复的作用。比如现有一条model=A, number=1的记录,新数据是model=A, number=2,原来的判断会因为model和number都存在就跳过创建,但实际上这个新组合是不存在的,会导致正确的数据被遗漏。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

