Django import_export导入CSV报get() returned more than one错误
问题根因
报错本质是外键匹配逻辑的唯一性约束不满足:你使用cities_light存储全球地名数据时,地名的name字段不是全局唯一值——不同国家下可能存在同名的省/州(Region),不同省/州下可能存在同名的城市(City),你当前配置的ForeignKeyWidget仅用name单字段做外键查询,匹配City时会命中所有名为"Austin"的城市记录,自然触发MultipleObjectsReturned异常。
逻辑依据
django-import-export内置的ForeignKeyWidget默认查询逻辑为:
def get_object(self, value, row=None, *args, **kwargs): return self.get_queryset(value, row, *args, **kwargs).get(**{self.field: value})
即直接调用get()方法按指定字段查询匹配实例,要求查询条件必须能定位到唯一一条对应记录,一旦匹配到多条结果就会抛出你遇到的异常。
你当前的配置完全没有用到「国家-省/州-城市」的层级从属关系做过滤,单靠名称匹配必然会撞同名数据。
修复步骤
- 自定义三个层级关联的外键匹配组件,重写
ForeignKeyWidget的get_queryset方法,查询下级地名时自动带上上级地名的过滤条件,保证查询结果唯一。 - 替换原有Resource配置里的默认
ForeignKeyWidget为自定义组件。
自定义外键组件代码
from import_export.widgets import ForeignKeyWidget from .models import Country, Region, City class CountryWidget(ForeignKeyWidget): def get_queryset(self, value, row, *args, **kwargs): return self.model.objects.filter(name=value) class RegionWidget(ForeignKeyWidget): def get_queryset(self, value, row, *args, **kwargs): # 匹配省份时追加所属国家过滤,避免跨国家同名省份冲突 return self.model.objects.filter( name=value, country__name=row.get("country") ) class CityWidget(ForeignKeyWidget): def get_queryset(self, value, row, *args, **kwargs): # 匹配城市时追加所属省份、所属国家过滤,避免跨区域同名城市冲突 return self.model.objects.filter( name=value, region__name=row.get("region"), region__country__name=row.get("country") )
修改后的Resource配置
class JobPostResource(resources.ModelResource): country = fields.Field( column_name='country', attribute='country', widget=CountryWidget(Country, 'name')) region = fields.Field( column_name='region', attribute='region', widget=RegionWidget(Region, 'name')) city = fields.Field( column_name='city', attribute='city', widget=CityWidget(City, 'name')) class Meta: model = JobPost export_order = ('id', 'title', 'company', 'urlCompany', 'urlApplication', 'contactEmail', 'jobType', 'country', 'region', 'city', 'createdAt', 'remainingDays', 'valid', 'visible', 'description') fields = ('id', 'title', 'company', 'urlCompany', 'urlApplication', 'contactEmail', 'jobType', 'country', 'region', 'city', 'createdAt', 'remainingDays', 'valid', 'visible', 'description')
可选优化
- 如果需要100%避免同名冲突,可以在导出时加入
cities_light自带的geoname_id字段(全球地名唯一标识),导入时优先用geoname_id做外键匹配,完全不会出现重名问题。
内容的提问来源于stack exchange,提问作者strontivm
相关产品推荐
相关产品推荐

