Django读取CSV文件用bulk_create创建对象时如何建立多对多关联
你的实现思路整体正确,通过bulk_create批量创建GS实例减少数据库IO的优化方向是对的,只需要补充多对多中间表的批量插入逻辑即可完成需求,具体实现如下:
实现步骤
- 遍历CSV行时,同时存储GS实例和对应关联的语言编码列表,方便后续匹配
- 利用Django
bulk_create自动填充主键的特性(PostgreSQL、MySQL 5.7+等主流数据库均支持),直接获取批量创建后的GS实例ID - 提前将所有用到的Lang对象转为编码到ID的映射字典,避免重复查询数据库
- 获取多对多字段自动生成的中间表模型,批量插入关联数据
完整修改后代码
def handle(self, *args, **options): path = 'path/to/file.csv' df = pd.read_csv(path) # 存储(GS实例, 关联语言编码列表)的配对关系 gs_lang_pairs = [] all_lang_codes = set() for i, row in df.iterrows(): # 处理语言编码 lang_codes = [c.strip() for c in row['Lang'].split(';')] all_lang_codes.update(lang_codes) # 创建GS实例暂存 segment = GS(name=row['Name']) gs_lang_pairs.append((segment, lang_codes)) # 批量创建GS实例,执行后实例会自动填充id主键 GS.objects.bulk_create([pair[0] for pair in gs_lang_pairs]) # 一次性查询所有用到的Lang对象,构建编码到ID的映射 lang_map = {lang.code: lang.id for lang in Lang.objects.filter(code__in=all_lang_codes)} # 获取多对多中间表模型 GSLangThrough = GS.country_code.through # 组装所有中间表记录 through_records = [] for gs, lang_codes in gs_lang_pairs: for code in lang_codes: lang_id = lang_map.get(code) if lang_id: # 过滤不存在的编码避免报错 through_records.append(GSLangThrough(gs_id=gs.id, lang_id=lang_id)) # 批量插入关联关系 GSLangThrough.objects.bulk_create(through_records)
注意事项
- 如果使用的数据库不支持
bulk_create返回主键,可在批量创建GS后,通过GS.objects.filter(name__in=[pair[0].name for pair in gs_lang_pairs])查询所有已创建的实例,再和原始行配对即可,需保证GS的name字段唯一 - 该方案全程仅执行3次数据库写入/查询操作,性能远高于逐行创建实例、逐行添加关联的实现方式
内容的提问来源于stack exchange,提问作者Jekson
相关产品推荐
相关产品推荐

