Repository: django-import-export/django-import-export

Issue:
V4: _check_import_id_fields doesn't produce intended error message.
**Describe the bug**
With V4 I have started getting following errors on `django-hordak` tests (for some reason it updates to pre versions even if it is not requested):

```
  File "/home/runner/work/django-hordak/django-hordak/hordak/views/statement_csv_import.py", line 84, in post
    self.result = resource.import_data(
                  ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/django_import_export-4.0.0b2-py3.12.egg/import_export/resources.py", line 799, in import_data
    result = self.import_data_inner(
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/django_import_export-4.0.0b2-py3.12.egg/import_export/resources.py", line 835, in import_data_inner
    self._check_import_id_fields(dataset.headers)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/django_import_export-4.0.0b2-py3.12.egg/import_export/resources.py", line 1068, in _check_import_id_fields
    import_id_fields = [self.fields[f] for f in self.get_import_id_fields()]
                        ~~~~~~~~~~~^^^
KeyError: 'id'
```

(https://github.com/adamcharnock/django-hordak/actions/runs/7421188620/job/20194029428)

I expect, that the `_check_import_id_fields` function should provide better error output like `The following import_id_fields are not present in the dataset` in such cases.

**Versions (please complete the following information):**
 - Django Import Export: 4.0.0b2
 - Python 3.8-3.12
 - Django 4.2-5.0


Discussion:
Thanks Petr - can you verify it is a regression in v4?  Does it work ok in 3.3.x?
@matthewhegarty Not sure if regression, the same tests are passing in 3.3.5, but the `_check_import_id_fields` is not present in the `main` branch.
I was expecting that the Resource in `django-hordak` have some problem which this new check is detecting, but I am not yet sure what the problem is. The resource (https://github.com/adamcharnock/django-hordak/blob/master/hordak/resources.py) is defined as:

```python
class StatementLineResource(resources.ModelResource):
    class Meta:
        model = StatementLine
        fields = ("date", "amount", "description")
```

when I add `import_id_fields = ()` the test starts to pass. I am not sure why I can't add `id` to the `fields`, it ends up with `import_export.exceptions.FieldError: The following import_id_fields are not present in the dataset: id`



Resolving patch:
diff --git a/import_export/resources.py b/import_export/resources.py
--- a/import_export/resources.py
+++ b/import_export/resources.py
@@ -1117,8 +1117,15 @@ def _is_dry_run(self, kwargs):
         return kwargs.get("dry_run", False)
 
     def _check_import_id_fields(self, headers):
-        import_id_fields = [self.fields[f] for f in self.get_import_id_fields()]
+        import_id_fields = list()
         missing_fields = list()
+
+        for field_name in self.get_import_id_fields():
+            if field_name not in self.fields:
+                missing_fields.append(field_name)
+            else:
+                import_id_fields.append(self.fields[field_name])
+
         for field in import_id_fields:
             if not headers or field.column_name not in headers:
                 # escape to be safe (exception could end up in logs)
@@ -1128,8 +1135,8 @@ def _check_import_id_fields(self, headers):
         if missing_fields:
             raise exceptions.FieldError(
                 _(
-                    "The following import_id_fields are not present in the dataset: %s"
-                    % ", ".join(missing_fields)
+                    "The following fields are declared in 'import_id_fields' but "
+                    "are not present in the resource: %s" % ", ".join(missing_fields)
                 )
             )
 


Test patch:
diff --git a/tests/core/tests/test_resources/test_import_export.py b/tests/core/tests/test_resources/test_import_export.py
--- a/tests/core/tests/test_resources/test_import_export.py
+++ b/tests/core/tests/test_resources/test_import_export.py
@@ -281,12 +281,34 @@ def test_custom_column_name_warns_if_not_present(self):
         dataset = tablib.Dataset(
             *[(self.book.pk, "Some book")], headers=["id", "wrong_name"]
         )
-        with self.assertRaisesRegex(
-            exceptions.FieldError,
-            "The following import_id_fields are not present "
-            "in the dataset: book_name",
-        ):
+        with self.assertRaises(exceptions.FieldError) as e:
             self.resource.import_data(dataset)
+        self.assertEqual(
+            "The following fields are declared in 'import_id_fields' "
+            "but are not present in the resource: book_name",
+            str(e.exception),
+        )
+
+    def test_missing_import_id_field_raises_exception(self):
+        class TestBookResource(resources.ModelResource):
+            class Meta:
+                model = Book
+                import_id_fields = ("id", "a", "b")
+
+        resource = TestBookResource()
+
+        book = Book.objects.create(name="Some book")
+        row = [book.pk, "Some book"]
+        dataset = tablib.Dataset(*[row], headers=["id", "name"])
+        dataset.append(row)
+
+        with self.assertRaises(exceptions.FieldError) as e:
+            resource.import_data(dataset)
+        self.assertEqual(
+            "The following fields are declared in 'import_id_fields' "
+            "but are not present in the resource: a, b",
+            str(e.exception),
+        )
 
     def test_multiple_import_id_fields(self):
         class BookResource(resources.ModelResource):
@@ -299,12 +321,13 @@ class Meta:
             *[(self.book.pk, "Goldeneye", "ian.fleming@example.com")],
             headers=["A", "name", "B"],
         )
-        with self.assertRaisesRegex(
-            exceptions.FieldError,
-            "The following import_id_fields are not present "
-            "in the dataset: id, author_email",
-        ):
+        with self.assertRaises(exceptions.FieldError) as e:
             self.resource.import_data(dataset)
+        self.assertEqual(
+            "The following fields are declared in 'import_id_fields' "
+            "but are not present in the resource: id, author_email",
+            str(e.exception),
+        )
 
 
 class ImportWithMissingFields(TestCase):
diff --git a/tests/core/tests/test_resources/test_modelresource/test_error_handling.py b/tests/core/tests/test_resources/test_modelresource/test_error_handling.py
--- a/tests/core/tests/test_resources/test_modelresource/test_error_handling.py
+++ b/tests/core/tests/test_resources/test_modelresource/test_error_handling.py
@@ -80,11 +80,13 @@ def test_import_data_raises_field_specific_validation_errors_with_skip_unchanged
 
     def test_import_data_empty_dataset_with_collect_failed_rows(self):
         resource = AuthorResource()
-        with self.assertRaisesRegex(
-            exceptions.FieldError,
-            "The following import_id_fields are not present in the dataset: id",
-        ):
+        with self.assertRaises(exceptions.FieldError) as e:
             resource.import_data(tablib.Dataset(), collect_failed_rows=True)
+        self.assertEqual(
+            "The following fields are declared in 'import_id_fields' "
+            "but are not present in the resource: id",
+            str(e.exception),
+        )
 
     @ignore_widget_deprecation_warning
     def test_collect_failed_rows(self):