Django import-export使用ForeignKeyWidget导入外键出现KeyError: 'id'如何解决
问题原因
你遇到的KeyError: 'id'报错由多个配置错误叠加导致:
- Admin类中
resource_class属性拼写错误,你写的recource_class属于无效配置,自定义的Resource规则完全没有生效,导入时使用默认生成的Resource规则。 - 默认Resource规则会使用模型默认主键
id作为导入时的唯一标识字段,但你的Clockin_Department模型主键是depid,不存在id字段,且你的Resource配置中也没有包含该字段。 - Resource的Meta配置中
fields传入了单个字符串,会被import-export识别为可迭代对象拆分为单个字符,完全不符合字段配置的预期。 - 额外问题:
Clockin_Users模型的__str__方法返回不存在的self.name属性,后续调用字符串格式化时会触发额外报错。
修复步骤
- 修正Admin类的属性拼写错误,确保自定义Resource生效
- 调整Resource的Meta配置,显式指定主键字段和导入标识字段
- 修复模型的
__str__方法错误 - 根据外键匹配规则调整ForeignKeyWidget参数(如果你的导入文件中
clockinusers列存储的是用户的userid而非主键id,需要显式指定匹配字段)
修复后完整代码
模型部分修复
class Clockin_Users(models.Model): id = models.AutoField(db_column='ID', primary_key=True) userid = models.IntegerField(db_column='UserID', unique=True) username = models.CharField(db_column='UserName', max_length=20, blank=True) facecount = models.IntegerField(db_column='FaceCount', blank=True, null=True) userid9 = models.CharField(db_column='UserID9', max_length=10, blank=True, null=True) depid = models.IntegerField(db_column='DepID', blank=True, null=True) empno = models.CharField(db_column='EMPNO', max_length=50, blank=True, null=True) def __str__(self): # 修复返回不存在的name字段问题 return self.username class Clockin_Department(models.Model): clockinusers = models.ForeignKey(Clockin_Users, on_delete=models.CASCADE) depid = models.AutoField(db_column='DepID', primary_key=True) departmentname = models.CharField(db_column='DepartmentName', max_length=100, blank=True, null=True) def __str__(self): return self.departmentname
Resource配置修复
class ClockinDepartmentResource(resources.ModelResource): # 如果clockinusers列存储的是用户的userid,就把widget改成ForeignKeyWidget(Clockin_Users, 'userid') clockinusers = fields.Field( column_name='clockinusers', attribute='clockinusers', widget=ForeignKeyWidget(Clockin_Users) ) class Meta: model = Clockin_Department # 必须传入元组/列表,按需添加需要导入的字段 fields = ('clockinusers', 'departmentname', 'depid') # 显式指定导入时用来判断更新/新增的唯一标识字段,匹配模型主键 import_id_fields = ('depid',) # 如果是纯新增数据不需要更新现有记录,不需要导入depid的话,可以改成: # import_id_fields = ('clockinusers', 'departmentname') # 用外键+部门名组合判断重复,也可以设置skip_diff=True跳过重复校验直接新增
Admin配置修复
class ClockinDepartmentAdmin(ImportExportModelAdmin): list_display = ('clockinusers', 'depid', 'departmentname') # 修正拼写错误 resource_class = ClockinDepartmentResource admin.site.register(Clockin_Department, ClockinDepartmentAdmin)
导入文件调整说明
如果保留import_id_fields = ('depid',)配置,导入文件需要新增表头为depid的列(之前你加id列无效是因为模型主键是depid不是id);如果是纯新增不需要更新,按上面注释修改import_id_fields配置后不需要加depid列。
内容的提问来源于stack exchange,提问作者user11766958
相关产品推荐
相关产品推荐

