Django-import-export:访问ModelResource未关联的文件字段问题
我来帮你解决这个问题,咱们一步步来梳理:
问题根源
你遇到的FieldError是因为在QuestionResource里把client字段的attribute设为了'client',但你的Question模型根本没有这个字段——import-export尝试把Excel里的client值写入Question模型时,自然找不到对应的字段,所以报错了。
你的核心需求是:用Excel里的client值创建/获取Client实例,再把这个实例关联到Venue、Event这些外键模型上,而不需要把client作为Question的字段。下面是具体的解决方案:
步骤1:重构自定义Widget,减少重复代码
首先咱们把重复的外键创建逻辑统一成一个通用Widget,避免写多个重复类:
from import_export.widgets import ForeignKeyWidget class ForeignKeyWidgetWithCreation(ForeignKeyWidget): def __init__(self, model, field='pk', create=False, *args, **kwargs): super().__init__(model, field, *args, **kwargs) self.create = create def clean(self, value, row=None, *args, **kwargs): if not value: return None # 如果需要自动创建,就用get_or_create if self.create: instance, _ = self.model.objects.get_or_create(**{self.field: value}) return instance # 不需要创建的话,按原逻辑查询 return super().clean(value, row, *args, **kwargs)
步骤2:修改需要关联Client的Widget(Venue/Event)
针对Venue和Event需要绑定Client的需求,咱们单独写Widget,通过row参数读取Excel里的client值:
# Venue专属Widget:创建Venue时自动关联对应的Client class VenueWidget(ForeignKeyWidget): def __init__(self, model, field='venue', *args, **kwargs): super().__init__(model, field, *args, **kwargs) # 复用上面的通用Widget处理Client的创建/获取 self.client_widget = ForeignKeyWidgetWithCreation(Client, 'name', create=True) def clean(self, value, row=None, *args, **kwargs): if not value: return None # 从当前行获取client值,得到Client实例 client_instance = self.client_widget.clean(row['client'], row, *args, **kwargs) # 创建/获取绑定了Client的Venue venue_instance, _ = self.model.objects.get_or_create(venue=value, client=client_instance) return venue_instance # Event专属Widget:逻辑和Venue一致 class EventWidget(ForeignKeyWidget): def __init__(self, model, field='event', *args, **kwargs): super().__init__(model, field, *args, **kwargs) self.client_widget = ForeignKeyWidgetWithCreation(Client, 'name', create=True) def clean(self, value, row=None, *args, **kwargs): if not value: return None client_instance = self.client_widget.clean(row['client'], row, *args, **kwargs) event_instance, _ = self.model.objects.get_or_create(event=value, client=client_instance) return event_instance
步骤3:修正QuestionResource的字段配置
把client字段改成虚拟字段(不绑定到Question模型的任何字段),只用来读取Excel里的值,供其他Widget使用:
from import_export import resources, fields from .models import Question, Category, Venue, Event, Client class QuestionResource(resources.ModelResource): category = fields.Field( column_name='category', attribute='category', widget=ForeignKeyWidgetWithCreation(Category, 'category', create=True) ) venue = fields.Field( column_name='venue', attribute='venue', widget=VenueWidget(Venue, 'venue') ) event = fields.Field( column_name='event', attribute='event', widget=EventWidget(Event, 'event') ) # 这里去掉attribute,只用来读取Excel中的client值,不写入Question模型 client = fields.Field(column_name='client') class Meta: model = Question fields = ['id', 'question', 'venue', 'category', 'answer', 'event', 'client']
为什么这样能解决问题?
- 移除
client字段的attribute后,import-export不会尝试把值写入Question模型,避免了字段找不到的报错; VenueWidget和EventWidget通过row['client']拿到Excel里的客户值,先创建/获取Client实例,再绑定到新创建的Venue/Event上;- 通用的
ForeignKeyWidgetWithCreation可以处理Category这类不需要关联Client的外键自动创建逻辑,减少代码冗余。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

