Django import-export foreignkey widget never called
I've set a breakpoint in the ForeignKeyWidget, yet it is never called while testing. Some popular LLM has no clue what I'm even asking, so here's all code including the uncalled breakpoint:
#models.py
class Place(BaseModel):
name = models.CharField(max_length=20)
class Locality(BaseModel):
place = models.ForeignKey(Place,null=True, blank=True,on_delete=models.CASCADE)
# admin.py
class PlaceForeignKeyWidget(ForeignKeyWidget):
def clean(self, value, row=None, **kwargs):
breakpoint() #Why never called?
try:
val = super().clean(value)
except Place.DoesNotExist:
val = Place.objects.create(name=row[r'place'])
return val
class LocalityResource(resources.ModelResource):
place = fields.Field(
attribute="place",
column_name="place",
widget=PlaceForeignKeyWidget(Place,"name")
)
class Meta:
model = Locality
import_id_fields=("zip_id")
# test.py
from import_export import resources
from crm.models import Locality
import tablib
import pytest
test_headers = [
"place",
"zip_id",
]
test_data = [
"NY",
"2494",
]
dataset = tablib.Dataset(test_data, headers=test_headers)
@pytest.mark.django_db
def test_locality_place_foreignkey():
# Act
locality_resource = resources.modelresource_factory(model=Locality)()
result = locality_resource.import_data(dataset,dry_run=False)
assert Locality.objects.count()
I suppose the Book,Author Example from the docs might work as well for that problem
modelresource_factory(model=Locality) creates a brand-new autogenerated resource class based only on the model, so it ignores your custom place field/widget entirely. That generated resource uses the default ForeignKeyWidget, not PlaceForeignKeyWidget. This is why clean() never runs.
Use your actual resource class instead:
@pytest.mark.django_db
def test_locality_place_foreignkey():
locality_resource = LocalityResource()
result = locality_resource.import_data(dataset, dry_run=False)
assert Locality.objects.count() == 1
Also make sure Place.name is unique if you're using it for FK lookup, otherwise ForeignKeyWidget can fail with multiple matches.
Your ForeignKeyWidget.clean method is not being called because resources.modelresource_factory creates a new ModelResource class dynamically, which does not include your custom place field definition and PlaceForeignKeyWidget from LocalityResource.
To fix this, use your explicitly defined LocalityResource class in your test:
# test.py
from crm.admin import LocalityResource # Assuming admin.py is importable
@pytest.mark.django_db
def test_locality_place_foreignkey():
# Act
locality_resource = LocalityResource() # Use your custom resource directly
result = locality_resource.import_data(dataset, dry_run=False)
assert Locality.objects.count()