Django执行bulk_create批量创建前如何在定义对象阶段判定重复数据
实现重复数据校验的方案
你原本设想的if data['title'] in videos:逻辑无法直接生效,因为videos列表里存储的是Video类实例,不是标题字符串,我们可以通过额外维护一个已处理标题的集合,实现你要的判断效果。
方案1:仅校验本次导入批次内的重复数据
修改后代码如下:
videos = [] throughs = [] # 新增:存储已处理过的标题,用于去重 processed_titles = set() # 新增:暂存每个视频对应的标签主键,批量创建完视频后再处理关联表 video_tag_map = [] for datas in files: for data in datas: # 完全符合你预期的判断逻辑,重复则直接跳过当前数据 if data["title"] in processed_titles: continue # 标题不重复则加入已处理集合 processed_titles.add(data["title"]) tags = data["tags"].split() tag_pks = list( set([Tag.objects.get_or_create(name=tag)[0].pk for tag in tags]) ) video = Video( title=data["title"], thumbnail_url=data["thumbnail_url"], preview_url=data["preview_url"], embed_url=data["embed_url"], embed_source=data["embed_source"], duration=data["duration"], published_at=data["published_at"], ) videos.append(video) # 暂存当前视频对应的标签主键 video_tag_map.append(tag_pks) # 批量创建视频,创建后video实例会自动填充主键(PostgreSQL、MySQL 5.7+等主流数据库均支持自动返回主键) Video.objects.bulk_create(videos) # 遍历创建好的视频和对应的标签,生成关联表数据 for video, tag_pks in zip(videos, video_tag_map): for tag_pk in tag_pks: throughs.append( Video.tags.through(video_id=video.pk, tag_id=tag_pk) ) Video.tags.through.objects.bulk_create(throughs)
方案2:同时校验数据库中已存在的重复数据
如果需要避免导入数据库中已经存储过的视频,只需要修改processed_titles的初始化逻辑,提前把数据库中已有的标题查出来即可:
# 初始化时直接加载数据库中所有已存视频标题 processed_titles = set(Video.objects.values_list("title", flat=True))
其余逻辑和方案1完全一致。
额外说明
原有代码中在创建Video实例后、bulk_create执行前就取video.pk的逻辑存在问题:未入库的实例没有主键值,会导致关联表数据插入失败,上面的代码已经调整了执行顺序,先批量创建视频拿到主键后再处理关联表。
内容的提问来源于stack exchange,提问作者Jvn
相关产品推荐
相关产品推荐

