Django中如何实现支持唯一性校验的bulk_create批量数据插入
Django批量插入唯一对象的高性能方案
要实现单次数据库请求完成唯一对象批量入库,同时保证不产生重复数据,只需结合数据库唯一约束和bulk_create的冲突处理参数即可,性能远高于循环调用get_or_create。
步骤1:给模型添加数据库层面的唯一约束
首先需要在模型中定义和get_or_create校验逻辑一致的唯一约束,让数据库可以识别重复条目:
# models.py from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) class Meta: # 定义first_name和last_name联合唯一,和原get_or_create的校验规则保持一致 constraints = [ models.UniqueConstraint(fields=['first_name', 'last_name'], name='unique_full_name') ]
添加约束后需要执行makemigrations和migrate命令,让约束在数据库中生效。
步骤2:调用bulk_create时开启冲突处理
Django 2.2及以上版本的bulk_create支持ignore_conflicts参数,开启后插入时遇到唯一约束冲突的条目会自动跳过,不会报错也不会产生重复数据,全程仅执行1次数据库请求:
# 准备批量插入的数据集,即使内部存在重复也不需要提前处理 person_list = [ Person(first_name='Leon', last_name='Mariano'), Person(first_name='Leon', last_name='Mariano'), Person(first_name='Bob', last_name='Smith'), ] # 单次请求完成插入,冲突条目自动忽略 Person.objects.bulk_create(person_list, ignore_conflicts=True)
扩展场景
如果你遇到重复条目时需要更新已有数据而非跳过,可以使用Django 4.1及以上版本支持的update_conflicts参数:
# 示例:假设Person模型新增age字段,姓名重复时更新age字段 person_list = [ Person(first_name='Leon', last_name='Mariano', age=30), Person(first_name='Bob', last_name='Smith', age=25), ] Person.objects.bulk_create( person_list, update_conflicts=True, unique_fields=['first_name', 'last_name'], # 指定判断冲突的唯一字段 fields=['age'] # 冲突时需要更新的字段 )
低版本Django兼容方案
如果使用的Django版本不支持ignore_conflicts参数,可以用2次数据库请求实现同等效果,性能仍远高于循环get_or_create:
- 先对要插入的数据集做内存去重
- 查询数据库中已存在的条目,过滤掉重复数据
- 把剩下的新数据批量插入
内容的提问来源于stack exchange,提问作者CbrRRider
相关产品推荐
相关产品推荐

