user11766958
user11766958

Reputation: 419

Django import-export foreign key

I am trying to import data with a foreign key following the guide from the Django import-export library (foreign key widget). But I am getting the following error , I have tried to add an additional column with the header name id but I still get the same error.

Errors

    Line number: 1 - 'id'
    None, 46, 19, LSD

    Traceback (most recent call last):
    File "/var/www/vfsc-env/lib/python3.6/site-packages/import_export/resources.py", line 635, in import_row
    instance, new = self.get_or_init_instance(instance_loader, row)
    File "/var/www/vfsc-env/lib/python3.6/site-packages/import_export/resources.py", line 330, in get_or_init_instance
    instance = self.get_instance(instance_loader, row)
    File "/var/www/vfsc-env/lib/python3.6/site-packages/import_export/resources.py", line 318, in get_instance
    self.fields[f] for f in self.get_import_id_fields()
    File "/var/www/vfsc-env/lib/python3.6/site-packages/import_export/resources.py", line 318, in <listcomp>
    self.fields[f] for f in self.get_import_id_fields()
    KeyError: 'id'

Here is what I did.

class Clockin_Users(models.Model):
    id = models.AutoField(db_column='ID', primary_key=True)  # Field name made lowercase.
    userid = models.IntegerField(db_column='UserID', unique=True)  # Field name made lowercase.
    username = models.CharField(db_column='UserName', max_length=20, blank=True,
    facecount = models.IntegerField(db_column='FaceCount', blank=True, null=True)  # Field name made lowercase.
    userid9 = models.CharField(db_column='UserID9', max_length=10, blank=True, null=True)  # Field name made lowercase.
    depid = models.IntegerField(db_column='DepID', blank=True, null=True)  # Field name made lowercase.
    empno = models.CharField(db_column='EMPNO', max_length=50, blank=True, null=True)  # Field name made lowercase.
    def __str__(self):
        return self.name

class Clockin_Department(models.Model):
    clockinusers = models.ForeignKey(Clockin_Users, on_delete=models.CASCADE)
    depid = models.AutoField(db_column='DepID', primary_key=True)  # Field name made lowercase.
    departmentname = models.CharField(db_column='DepartmentName', max_length=100, blank=True,
                                      null=True)  # Field name made lowercase
    def __str__(self):
        return self.departmentname

class ClockinDepartmentResource(resources.ModelResource):
    clockinusers = fields.Field(column_name='clockinusers', attribute='clockinusers',
                                widget=ForeignKeyWidget(Clockin_Users))

    class Meta:
        fields = 'clockinusers'

class ClockinDepartmentAdmin(ImportExportModelAdmin):
    list_display = ('clockinusers', 'depid', 'departmentname')
    recource_class = ClockinDepartmentResource


admin.site.register(Clockin_Department, ClockinDepartmentAdmin)

Upvotes: 2

Views: 2976

Answers (1)

Matthew Hegarty
Matthew Hegarty

Reputation: 4306

This issue comes up fairly frequently, so I'll try to give a comprehensive answer which might help others in future.

When you are importing a file using django-import-export, the file is going to be processed row by row. For each row, the import process is going to test whether the row corresponds to an existing stored instance, or whether a new instance is to be created.

In order to test whether the instance already exists, django-import-export needs to use a field (or a combination of fields) in the row being imported. The idea is that the field (or fields) will uniquely identify a single instance of the model type you are importing.

This is where the import_id_fields meta attribute comes in. You can use this declaration to indicate which field (or fields) should be used to uniquely identify the row. If you don't declare import_id_fields, then a default declaration is used, in which there is only one field: 'id'.

So we can now see the source of your error - the import process is trying to use the default 'id' field, but there is no corresponding field in your row.

To fix this, you will either need to include the 'id' field in your csv field, or if this is not possible, then choose some other field (or fields) that will uniquely identify the row.

In either case, ensure that you declare this field (or fields) in your fields attribute, for example:

class BookResource(resources.ModelResource):

    class Meta:
        model = Book
        import_id_fields = ('id',)
        fields = ('id', 'name', 'author', 'price',)

Note that if you have multiple rows which are identified by import_id_fields, then this is incorrect, because it should return either 0 or 1 rows. In this case, you will get a MultipleObjectsReturned error.

Upvotes: 9

Related Questions