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

Issue:
TypeError: Widget.__init__() got an unexpected keyword argument 'key_is_id' when upgrading from 3.8 to 4.0
After upgrading from version 3.8 to 4.0 I get the error `TypeError: Widget.__init__() got an unexpected keyword argument 'key_is_id'`. Full stack below.

```
(py_ptracker) root@euganeus:/opt/team_django# ./manage.py collectstatic
Traceback (most recent call last):
  File "/opt/team_django/./manage.py", line 22, in <module>
    main()
  File "/opt/team_django/./manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/core/management/__init__.py", line 416, in execute
    django.setup()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/apps/registry.py", line 124, in populate
    app_config.ready()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/contrib/admin/apps.py", line 27, in ready
    self.module.autodiscover()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/contrib/admin/__init__.py", line 52, in autodiscover
    autodiscover_modules("admin", register_to=site)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/utils/module_loading.py", line 58, in autodiscover_modules
    import_module("%s.%s" % (app_config.name, module_to_search))
  File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/opt/team_django/artsdb/admin.py", line 153, in <module>
    class ProjectResource(resources.ModelResource):
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/import_export/declarative.py", line 100, in __new__
    field = new_class.field_from_django_field(f.name, f, readonly=False)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/import_export/resources.py", line 1279, in field_from_django_field
    widget=FieldWidget(**widget_kwargs),
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Widget.__init__() got an unexpected keyword argument 'key_is_id'
```


Discussion:
Thanks for raising.  Is it possible you can test with #1805 and see if that resolves the issue.

Thank you. I now get the following:

```
Traceback (most recent call last):
  File "/opt/team_django/./manage.py", line 22, in <module>
    main()
  File "/opt/team_django/./manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/core/management/__init__.py", line 416, in execute
    django.setup()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/apps/registry.py", line 124, in populate
    app_config.ready()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/contrib/admin/apps.py", line 27, in ready
    self.module.autodiscover()
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/contrib/admin/__init__.py", line 52, in autodiscover
    autodiscover_modules("admin", register_to=site)
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/django/utils/module_loading.py", line 58, in autodiscover_modules
    import_module("%s.%s" % (app_config.name, module_to_search))
  File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/opt/team_django/artsdb/admin.py", line 153, in <module>
    class ProjectResource(resources.ModelResource):
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/import_export/declarative.py", line 100, in __new__
    field = new_class.field_from_django_field(f.name, f, readonly=False)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/py_ptracker/lib/python3.11/site-packages/import_export/resources.py", line 1289, in field_from_django_field
    widget=FieldWidget(**widget_kwargs),
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'str' object is not callable
```
ok - is it possible you can give me some steps to reproduce?  Can you identify which field in `ProjectResource` is causing the issue?
I have this in `admin.py`:

```
from import_export import resources
from import_export.admin import ImportExportModelAdmin

class ProjectResource(resources.ModelResource):
	class Meta:
		model = Project

class ProjectAdmin(ImportExportModelAdmin):
    resource_classes = [ProjectResource]
```


How can I identify the problematic field? Do I need to comment them one by one?
Are you able to post the field list for the `Project` model class?
That's my full `project` model:

```
from djmoney.models.fields import MoneyField
from smart_selects.db_fields import ChainedForeignKey

class Project(models.Model):

    STATUS_CHOICES = [
    [...]
    ]

    STAGE_CHOICES = [
    [...]
    ]

    title = models.CharField(max_length=200)
    project_number = models.DecimalField(max_digits=15, decimal_places=0, blank=True, null=True)
    funder = models.ForeignKey(Funder, on_delete=models.PROTECT, null=True, blank=True)
    scheme = ChainedForeignKey(
        Scheme,
        chained_field="funder",
        chained_model_field="funders",
        show_all=False,
        auto_choose=True,
        sort=True, null=True, blank=True)
    application_stage = models.CharField(choices=STAGE_CHOICES, max_length=30, null=True, blank=True)
    start_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)
    status = models.CharField(choices=STATUS_CHOICES, max_length=30, null=True, blank=True)
    submitted_on = models.DateField(blank=True, null=True)
    budget = MoneyField(max_digits=14, decimal_places=2, default_currency='GBP', null=True, blank=True)
    added_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT)
    added_on = models.DateField(auto_now_add=True)
    person = models.ManyToManyField(Person, through=PersonRole)
    collaboration = models.ManyToManyField(Organisation, through=CollaborationType, blank=True)
    notes = models.TextField(blank=True, null=True)
    funder_reference = models.CharField(max_length=15, blank=True, null=True)


    def __str__(self):
        return self.title

    @admin.display(description='Principal investigator')
    def get_PI(self):
        return [p for p in self.person.filter(personrole__person_role__contains="Principal investigator")]

    @admin.display(description='PI School')
    def get_PI_school(self):
        return [
            p.get_PI_school()
            for p in self.personrole_set.filter(
                person_role__contains="Principal investigator"
            )
        ]

    @admin.display(description='PI Subject')
    def get_PI_subject(self):
        return [
            p.get_PI_subject()
            for p in self.personrole_set.filter(
                person_role__contains="Principal investigator"
            )
        ]

    @admin.display(description='Partner') #currently not used
    def get_Partner(self):
        return [partner for partner in self.collaboration.filter(collaborationtype__collaboration_type__contains="Partner")]

    class Meta:
        verbose_name_plural = "Projects"
```
Presumably `ChainedForeignKey` comes from [this project](https://django-smart-selects.readthedocs.io/en/latest/usage.html#chainedforeignkey-options).
Do you want me to comment that field? It was working before upgrading to 4.0.
If you could try that it would be appreciated.  It would be ideal to identify which of your fields is causing the issue.
OK, I'll make a full database backup and comment the fields one by one.
ok thanks.  If it's easier and safer, you could use the [example app](https://django-import-export.readthedocs.io/en/latest/installation.html#example-app) and add fields from other packages.  My guess is that it will be the `ChainedForeignKey` or `MoneyField` which is the issue.  This is probably what I will end up doing, but if you can look into it, then it will speed up a resolution.
Hello @matthewhegarty , I can confirm that the issue is with the `ChainedForeignKey` field. It was working with version 3.8.

Resolving patch:
diff --git a/import_export/resources.py b/import_export/resources.py
--- a/import_export/resources.py
+++ b/import_export/resources.py
@@ -1264,6 +1264,8 @@ def widget_from_django_field(cls, f, default=widgets.Widget):
             for base_class in inspect.getmro(f.__class__):
                 if base_class.__name__ in cls.WIDGETS_MAP:
                     result = cls.WIDGETS_MAP[base_class.__name__]
+                    if isinstance(result, str):
+                        result = getattr(cls, result)(f)
                     break
 
             try:


Test patch:
diff --git a/tests/core/tests/test_model_resource_fields_generate_widgets.py b/tests/core/tests/test_model_resource_fields_generate_widgets.py
--- a/tests/core/tests/test_model_resource_fields_generate_widgets.py
+++ b/tests/core/tests/test_model_resource_fields_generate_widgets.py
@@ -7,10 +7,11 @@
 from django.contrib.postgres import search as postgres_search
 from django.contrib.postgres.fields import ranges as postgres_ranges
 from django.db import models
-from django.db.models.fields.related import RelatedField
+from django.db.models.fields.related import ForeignKey, RelatedField
 
 from import_export import widgets
 from import_export.resources import ModelResource
+from import_export.widgets import ForeignKeyWidget
 
 
 class ExampleResource(ModelResource):
@@ -188,3 +189,22 @@ def _get_django_fields_for_check_widget(self):
             postgres.RangeField(),
         ]
         return fields
+
+    def test_custom_fk_field(self):
+        # issue 1817 - if a 'custom' foreign key field is provided, then this should
+        # be handled when widgets are defined
+        class CustomForeignKey(ForeignKey):
+            def __init__(
+                self,
+                to,
+                on_delete,
+                **kwargs,
+            ):
+                super().__init__(to, on_delete, **kwargs)
+
+        resource_field = ModelResource.field_from_django_field(
+            "custom_fk",
+            CustomForeignKey(WithPositiveIntegerFields, on_delete=models.SET_NULL),
+            False,
+        )
+        self.assertEqual(ForeignKeyWidget, resource_field.widget.__class__)