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

Issue:
4.0 compatiblity with AutoSlugField - unexpected keyword argument 'allow_blank'
**Describe the bug**

It appears that 4.0 errors when used with AutoSlugField from django-extensions.

**To Reproduce**

```python
class Foo(models.Model)
    slug = AutoSlugField(populate_from=["name"], max_length=50)

class FooResource(resources.ModelResource):
    class Meta:
        model = Foo
```

```
File "/usr/local/lib/python3.12/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/lib/python3.12/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 'allow_blank'
```


**Versions (please complete the following information):**
 - Django Import Export: 4.0
 - Python 3.12
 - Django 5.0

**Expected behavior**

I'm not sure if this can be in scope, but django extensions is fairly popular and has worked prior. I'd expect an upgrade to not break it. I'm not sure how to work around id.

It works fine with 3.x or by replacing the AutoSlugField with a CharField.


Discussion:
Thanks for raising.  This is a valid bug.  

This is occurring because `SlugField` is identified as a subclass of `CharField` and the appropriate kwargs are derived for `CharWidget`.  However, the widget type is the default of `Widget` so the process crashes when passed the `CharWidget` kwargs.

Resolving patch:
diff --git a/import_export/resources.py b/import_export/resources.py
--- a/import_export/resources.py
+++ b/import_export/resources.py
@@ -1,4 +1,5 @@
 import functools
+import inspect
 import logging
 import traceback
 from collections import OrderedDict
@@ -1240,6 +1241,15 @@ def widget_from_django_field(cls, f, default=widgets.Widget):
             if isinstance(result, str):
                 result = getattr(cls, result)(f)
         else:
+            # issue 1804
+            # The field class may be in a third party library as a subclass
+            # of a standard field class.
+            # iterate base classes to determine the correct widget class to use.
+            for base_class in inspect.getmro(f.__class__):
+                if base_class.__name__ in cls.WIDGETS_MAP:
+                    result = cls.WIDGETS_MAP[base_class.__name__]
+                    break
+
             try:
                 from django.contrib.postgres.fields import ArrayField
             except ImportError:


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
@@ -1,6 +1,7 @@
 from unittest import TestCase
 
 import django
+from core.models import WithPositiveIntegerFields
 from django.contrib.contenttypes import fields as contenttype_fields
 from django.contrib.postgres import fields as postgres
 from django.contrib.postgres import search as postgres_search
@@ -11,8 +12,6 @@
 from import_export import widgets
 from import_export.resources import ModelResource
 
-from ..models import WithPositiveIntegerFields
-
 
 class ExampleResource(ModelResource):
     class Meta:
@@ -87,7 +86,6 @@ def _get_fields_with_expected_default_widget(self):
             models.GenericIPAddressField,
             models.ImageField,
             models.IPAddressField,
-            models.SlugField,
             models.TextField,
             models.UUIDField,
             postgres.BigIntegerRangeField,
@@ -99,12 +97,6 @@ def _get_fields_with_expected_default_widget(self):
             postgres.IntegerRangeField,
             postgres.RangeField,
         }
-        if django.VERSION < (5, 1):
-            ci_char_fields = {
-                postgres.CICharField,
-                postgres.CIEmailField,
-            }
-            expected_has_default_widget |= ci_char_fields
         return expected_has_default_widget
 
     def _get_expected_not_presented_in_test_field_subclasses(self):
diff --git a/tests/core/tests/test_resources/test_modelresource/test_widget.py b/tests/core/tests/test_resources/test_modelresource/test_widget.py
--- a/tests/core/tests/test_resources/test_modelresource/test_widget.py
+++ b/tests/core/tests/test_resources/test_modelresource/test_widget.py
@@ -1,5 +1,5 @@
 from core.tests.resources import BookResource
-from django.db.models import CharField
+from django.db.models import CharField, SlugField
 from django.test import TestCase
 
 from import_export import widgets
@@ -11,3 +11,9 @@ def test_widget_from_django_field_for_CharField_returns_CharWidget(self):
         resource = BookResource()
         w = resource.widget_from_django_field(f)
         self.assertEqual(widgets.CharWidget, w)
+
+    def test_widget_from_django_field_for_CharField_subclass_returns_CharWidget(self):
+        f = SlugField()
+        resource = BookResource()
+        w = resource.widget_from_django_field(f)
+        self.assertEqual(widgets.CharWidget, w)