Skip to content

Commit

Permalink
Quick & dirty fix for 974
Browse files Browse the repository at this point in the history
  • Loading branch information
PetrDlouhy committed Dec 15, 2023
1 parent 3fa68e2 commit 48654c4
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
12 changes: 10 additions & 2 deletions import_export/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.core.paginator import Paginator
from django.db import connections, router
from django.db.models import fields
from django.db.models.fields.related import ForeignKey, ForeignObjectRel
from django.db.models.query import QuerySet
from django.db.transaction import TransactionManagementError, set_rollback
from django.utils.encoding import force_str
Expand Down Expand Up @@ -1196,9 +1197,16 @@ def field_from_django_field(cls, field_name, django_field, readonly):

FieldWidget = cls.widget_from_django_field(django_field)
widget_kwargs = cls.widget_kwargs_for_field(field_name, django_field)

attribute = field_name
column_name = field_name
if isinstance(django_field, ForeignKey) and "__" not in column_name:
attribute += "_id"
widget_kwargs["key_is_id"] = True

field = cls.DEFAULT_RESOURCE_FIELD(
attribute=field_name,
column_name=field_name,
attribute=attribute,
column_name=column_name,
widget=FieldWidget(**widget_kwargs),
readonly=readonly,
default=django_field.default,
Expand Down
19 changes: 17 additions & 2 deletions import_export/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,17 @@ class Meta:
related object, default to False
"""

def __init__(self, model, field="pk", use_natural_foreign_keys=False, **kwargs):
def __init__(
self,
model,
field="pk",
use_natural_foreign_keys=False,
key_is_id=False,
**kwargs
):
self.model = model
self.field = field
self.key_is_id = key_is_id
self.use_natural_foreign_keys = use_natural_foreign_keys
super().__init__(**kwargs)

Expand Down Expand Up @@ -528,7 +536,10 @@ def clean(self, value, row=None, **kwargs):
return self.model.objects.get_by_natural_key(*value)
else:
lookup_kwargs = self.get_lookup_kwargs(value, row, **kwargs)
return self.get_queryset(value, row, **kwargs).get(**lookup_kwargs)
obj = self.get_queryset(value, row, **kwargs).get(**lookup_kwargs)
if self.key_is_id:
return obj.id
return obj
else:
return None

Expand All @@ -551,6 +562,10 @@ def render(self, value, obj=None):
``coerce_to_string`` has no effect on the return value.
"""
self._obj_deprecation_warning(obj)

if self.key_is_id:
return value

if value is None:
return ""

Expand Down
17 changes: 17 additions & 0 deletions tests/core/tests/test_resources/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,23 @@ def test_export(self):
dataset = self.resource.export(queryset=Book.objects.all())
self.assertEqual(len(dataset), 1)

def test_export_with_foreign_keys(self):
"""
Test that export() containing foreign keys doesn't generate
extra query fore every row.
Fix #794
"""
author = Author.objects.create()
self.book.author = author
self.book.save()
Book.objects.create(name="Second book", author=Author.objects.create())
Book.objects.create(name="Third book", author=Author.objects.create())

with self.assertNumQueries(3):
dataset = self.resource.export(Book.objects.prefetch_related("categories"))
self.assertEqual(dataset.dict[0]["author"], author.pk)
self.assertEqual(len(dataset), 3)

@ignore_widget_deprecation_warning
def test_export_iterable(self):
with self.assertNumQueries(2):
Expand Down

0 comments on commit 48654c4

Please sign in to comment.