You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用django-import-export导入CSV到一对多关联多表?求示例

Django-Import-Export 一对多关联数据导入实现方案

针对你需要将扁平CSV中的多组act_X_*字段解析为一对多关联副表的场景,以下是基于django-import-export的最佳实践实现:

1. 补全主表模型(SlateDoc)

首先确保SlateDoc模型包含CSV中对应的主表字段:

# models.py
from django.db import models

class SlateDoc(models.Model):
    filename = models.CharField(max_length=255)
    int_house_num = models.CharField(max_length=20)
    series_title = models.CharField(max_length=255)
    episode_title = models.CharField(max_length=255)
    producer = models.CharField(max_length=255)
    # 其他未列出的字段按需添加

    def __str__(self):
        return self.filename

class ActTimecodes(models.Model):
    slatedoc = models.ForeignKey(
        SlateDoc, 
        on_delete=models.CASCADE, 
        related_name="acts"
    )
    act_number = models.IntegerField(verbose_name="Act", default=1)
    tc_in = models.CharField(max_length=11, default="00:00:00:00")
    tc_out = models.CharField(max_length=11, default="00:00:00:00")
    dur = models.CharField(max_length=11, default="00:00:00:00")

    class Meta:
        ordering = ["act_number", "tc_in", "tc_out"]

2. 自定义Resource类

创建SlateDocResource,重写导入逻辑以处理一对多关联:

# resources.py
from import_export import resources, fields
from .models import SlateDoc, ActTimecodes

class SlateDocResource(resources.ModelResource):
    # 映射CSV列到主表字段
    filename = fields.Field(column_name='filename', attribute='filename')
    int_house_num = fields.Field(column_name='int_house_num', attribute='int_house_num')
    series_title = fields.Field(column_name='series_title', attribute='series_title')
    episode_title = fields.Field(column_name='episode_title', attribute='episode_title')
    producer = fields.Field(column_name='producer', attribute='producer')

    class Meta:
        model = SlateDoc
        import_id_fields = ['id']  # 用id匹配或更新现有记录
        fields = ('id', 'filename', 'int_house_num', 'series_title', 'episode_title', 'producer')

    def before_save_instance(self, instance, row, **kwargs):
        # 将当前CSV行数据临时存储到实例属性
        instance._import_row = row

    def save_instance(self, instance, using_transactions=True, dry_run=False):
        # 先保存主表实例
        super().save_instance(instance, using_transactions, dry_run)
        
        # 预览模式(dry_run)不写入副表数据
        if dry_run:
            return
        
        row = instance._import_row
        act_instances = []
        max_acts = 6  # 根据CSV中的最大act数量调整

        # 遍历所有act编号,解析对应字段
        for act_num in range(1, max_acts + 1):
            act_num_str = f"{act_num:02d}"
            tc_in = row.get(f'act_{act_num_str}_in')
            tc_out = row.get(f'act_{act_num_str}_out')
            dur = row.get(f'act_{act_num_str}_dur')

            # 跳过空值的act记录
            if not all([tc_in, tc_out, dur]):
                continue

            # 构造副表实例
            act_instances.append(ActTimecodes(
                slatedoc=instance,
                act_number=act_num,
                tc_in=tc_in,
                tc_out=tc_out,
                dur=dur
            ))

        # 批量创建副表记录,提升导入效率
        if act_instances:
            ActTimecodes.objects.bulk_create(act_instances)

3. 后台管理配置

在admin中注册Resource,启用导入功能:

# admin.py
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from .models import SlateDoc, ActTimecodes
from .resources import SlateDocResource

class SlateDocAdmin(ImportExportModelAdmin):
    resource_class = SlateDocResource
    list_display = ('filename', 'series_title', 'episode_title')

admin.site.register(SlateDoc, SlateDocAdmin)
admin.site.register(ActTimecodes)

关键实现说明

  • before_save_instance:临时存储当前CSV行数据,供后续解析副表字段使用。
  • save_instance:先完成主表实例的保存,再批量创建关联的ActTimecodes记录,确保外键关联有效。
  • 批量创建:使用bulk_create替代循环create,大幅提升大量数据导入的性能。
  • 空值过滤:跳过缺失关键字段的act记录,避免无效数据入库。
  • 预览模式兼容:dry_run判断确保导入预览时不会写入副表数据。

内容的提问来源于stack exchange,提问作者stevec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 08:20:26