I am trying to import an excel file with some data to a model with foreignKey
but I get KeyError: 'id'
I have exported the data and imported same exported file with success, when I add new data to same file the problem shows up.
Import:
This importer will import the following fields: name, Brand__BrandName, gender, stockPrice
File to import: Format: xlsx Errors Line number: 1 - 'id' p3, B1, unisex, 99999
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 639, in import_row
instance, new = self.get_or_init_instance(instance_loader, row)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 334, in get_or_init_instance
instance = self.get_instance(instance_loader, row)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 321, in get_instance
import_id_fields = [
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 322, in <listcomp>
self.fields[f] for f in self.get_import_id_fields()
KeyError: 'id'
Line number: 2 - 'id' p2, b2, unisex, 99999
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 639, in import_row
instance, new = self.get_or_init_instance(instance_loader, row)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 334, in get_or_init_instance
instance = self.get_instance(instance_loader, row)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 321, in get_instance
import_id_fields = [
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/import_export/resources.py", line 322, in <listcomp>
self.fields[f] for f in self.get_import_id_fields()
KeyError: 'id'
my model:
from django.db import models
from django.utils import timezone
from django.conf import settings
class Brand(models.Model):
BrandName= models.CharField(max_length=40)
def __str__(self):
return self.BrandName
class Perfume(models.Model):
genderChoice = (
('unisex','unisex'), ('male', 'male'), ('female', 'female'))
name = models.CharField(max_length=50)
Brand= models.ForeignKey(to=Brand,on_delete=models.CASCADE, blank=False)
gender = models.CharField(max_length=7, choices=genderChoice, default='unisex')
description = models.TextField()
stockPrice = models.IntegerField(default=99999)
active = models.BooleanField(default=False)
show_for_consumer = models.BooleanField(default=False)
created = models.DateField()
author =models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Pricing(models.Model):
product =models.ForeignKey(Perfume, on_delete=models.CASCADE,related_name='prices')
price= models.IntegerField()
volume= models.IntegerField()
def __str__(self):
return 'Perfume {} - Price{} - Volume {}'.format(self.product.name,self.price, self.volume)
my admin.py
from django.contrib import admin
from .models import Perfume, Brand, Pricing
from import_export.admin import ImportExportModelAdmin
from import_export import resources, fields
from import_export.widgets import ForeignKeyWidget
# Register your models here.
class PriceInline(admin.StackedInline):
model = Pricing
class ModelInline(admin.StackedInline):
model = Perfume
class BrandAdmin(admin.ModelAdmin):
model = Brand
inlines = [ModelInline,]
#for import settings
class ProductResorce(resources.ModelResource):
class Meta:
model = Perfume
exclude = ('active', 'show_for_consumer', 'created', 'author')
fields=('name', 'Brand__BrandName', 'gender', 'stockPrice')
export_order = ('name', 'Brand__BrandName', 'gender', 'stockPrice')
#showing in product add
class ProductImportAdmin(ImportExportModelAdmin):
resource_class = ProductResorce
list_display = ['name', 'gender', 'Brand']
fields = ['name', 'gender', 'Brand', 'author', 'created', 'stockPrice', 'description']
inlines = [PriceInline]
admin.site.register(Brand, BrandAdmin)
admin.site.register(Perfume, ProductImportAdmin)
The problem is that when you import the file for the second time, the import process will try to match each row against existing records in the database, and try to update the stored data.
It will use a field called 'id' by default to do this (docs).
However, you have no field called 'id' in your dataset or on your resource (
ProductResorce
), hence it throws the error you are seeing.To fix it, you should add a field which uniquely identifies each entry, and declare it on the resource. For example if you use a field called 'sku', you can declare it on your resource:
You can use more than one field as the unique identifier.
Having a unique identifier is really useful because it means you can safely re-run jobs without the risk of failures or creating duplicates.