Django import-export导入不存在外键:如何创建关联Board?
Django import-export 无法创建Board关联对象问题
我在使用Django import-export时,已能在导入过程中创建Person和Organization实例,但无法生成对应的Board关联对象,导入结果为OrderedDict([('new', 0), ('update', 0), ('delete', 0), ('skip', 0), ('error', 0), ('invalid', 1)]),请问缺失的Board创建步骤在哪里?
模型代码
class Person(BaseModel): organizations = models.ManyToManyField("Organization", blank=True, through="Board") class Organization(BaseModel): people = models.ManyToManyField("Person", blank=True, through="Board") class Board(BaseModel): person = models.ForeignKey(Person, on_delete=models.CASCADE) organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
测试代码
from django.test import TestCase import tablib from import_export import resources class BoardResource(resources.ModelResource): def before_import_row(self, row, **kwargs): org_name_1 = row["organization"] o=Organization.objects.get_or_create(name_1=org_name_1, defaults={"name_1": org_name_1}) person_firstname = row["person"] p=Person.objects.get_or_create(firstname=person_firstname, defaults={"firstname": person_firstname}) class Meta: model = Board dataset = tablib.Dataset(['','john','acme'], headers=['id','person','organization']) class TestCase(TestCase): def test_basic_import(self): board_resource = BoardResource() result = board_resource.import_data(dataset, dry_run=False) print(result.totals) assert not result.has_errors()
环境信息
- Python 3.8
- Django 4.2
- Import-Export 4.11
- Pytest-Django
问题分析
核心问题是BoardResource仅在before_import_row中创建了Person和Organization实例,但未将这两个实例的关联ID写入当前行数据。import-export无法自动将名称映射为外键ID,导致该行被判定为无效,最终无法创建Board对象。
修复方案
1. 修改before_import_row方法,写入关联ID
调整方法,将创建的Person和Organization的ID赋值给行数据对应的外键字段,让import-export能识别并创建关联:
class BoardResource(resources.ModelResource): def before_import_row(self, row, **kwargs): org_name_1 = row["organization"] # 提取get_or_create返回的实例对象 o, _ = Organization.objects.get_or_create(name_1=org_name_1, defaults={"name_1": org_name_1}) # 将Organization的ID写入行数据,对应Board的organization外键 row["organization"] = o.id person_firstname = row["person"] p, _ = Person.objects.get_or_create(firstname=person_firstname, defaults={"firstname": person_firstname}) # 将Person的ID写入行数据,对应Board的person外键 row["person"] = p.id class Meta: model = Board # 明确指定导入字段,确保外键字段被正确处理 fields = ('id', 'person', 'organization')
2. 验证修复效果
运行测试后,result.totals应显示new=1,表示成功创建了一个Board实例,断言assert not result.has_errors()会通过。
关键注意点
get_or_create返回元组(实例, 是否新建),必须取第一个元素获取实例对象。- 外键字段需要的是关联对象的ID而非名称,必须将ID赋值回行数据,import-export才能正确匹配。
- 如果希望用名称而非ID导入,可以自定义
ForeignKeyWidget实现名称到ID的转换,但直接替换ID是当前场景下最直接的方案。
内容的提问来源于stack exchange,提问作者jjk
相关产品推荐
相关产品推荐

