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

Issue:
Importing and OneToOne relationship
Hi, i am using the following structure for my project and i am struggling with importing data from a xlsx sheet:

```python
# models.py

class MotorType(models.Model):
    """ Represents a motor type"""
    name = models.CharField(max_length=200)

class MotorStaff(models.Model):
    """ Extends the django user model by a separate model relationship which holds additional user
    attributes
    """
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # by default a new user is not a staff member which take care of the motor administration
    is_motor_staff = models.BooleanField(default=False)

    def __str__(self):
        return u"{}".format(self.user.username)

class Motor(models.Model):
    """ Represent a single motor instance """
    motor_type = models.ForeignKey(MotorType, on_delete=models.CASCADE, default=None)
    internal_id = models.CharField(max_length=200)
    date_of_receipt = models.DateField(help_text="""Date at which the motor was received""")
    responsible_person = models.ForeignKey(MotorStaff,
                                           on_delete=models.SET_NULL,
                                           default=None,
                                           blank=True,
                                           null=True,
                                           limit_choices_to={'is_motor_staff': True})


    def __str__(self):
        return u"{}".format(self.internal_id)


# resource.py

class FullNameForeignKeyWidget(ForeignKeyWidget):
    def get_queryset(self, value, row):
        objects = self.model.objects.filter(
            user__username__iexact=row["responsible_person"]
        )
        return objects

class MotorResource(resources.ModelResource):
    motor_type = fields.Field(
        column_name='motor_type',
        attribute='motor_type',
        widget=ForeignKeyWidget(MotorType, 'name')
    )

    responsible_person = fields.Field(
        column_name='responsible_person',
        attribute='responsible_person',
        widget=FullNameForeignKeyWidget(MotorStaff)
    )

    class Meta:
        model = Motor
        skip_unchanged = True
        report_skipped = True
        raise_errors = True
        import_id_fields = ('internal_id',)
        exclude = ('id', )
```

The identification of `motor_type` works without any problems. But trying to identify the final user using the `responsible_person` column and a string of 'test_user' still gives:

`Line number: 1 - Column 'responsible_person': invalid literal for int() with base 10: 'test_user' `

When debugging i can see that the correct user object is found in the `get_queryset` method of `FullNameForeignKeyWidget` as a QuerySet with one element.

If i change the widget to
```widget=FullNameForeignKeyWidget(MotorStaff, 'user__username')```
the objects is found and gets passed on. But this finally throws:

```
Line number: 1 - 'MotorStaff' object has no attribute 'user__username'

Traceback (most recent call last):
File "...lib\site-packages\import_export\resources.py", line 477, in import_row
diff.compare_with(self, instance, dry_run)
File "...lib\site-packages\import_export\resources.py", line 170, in compare_with
self.right = self._export_resource_fields(resource, instance)
File "...lib\site-packages\import_export\resources.py", line 186, in _export_resource_fields
return [resource.export_field(f, instance) if instance else "" for f in resource.get_user_visible_fields()]
File "...lib\site-packages\import_export\resources.py", line 186, in <listcomp>
return [resource.export_field(f, instance) if instance else "" for f in resource.get_user_visible_fields()]
File "...lib\site-packages\import_export\resources.py", line 615, in export_field
return field.export(obj)
File "...lib\site-packages\import_export\fields.py", line 132, in export
return self.widget.render(value, obj)
File "...lib\site-packages\import_export\widgets.py", line 346, in render
return getattr(value, self.field)
AttributeError: 'MotorStaff' object has no attribute 'user__username'
```

Any ideas how i could succeed here?

django-import-export version used is: 1.0.1


Discussion:
I solved it using the following dehydrate method:

```python
class MotorResource(resources.ModelResource):
...
    def dehydrate_responsible_person(self, motor):
        if motor.responsible_person is not None:
            return "%s" % motor.responsible_person.user.username
        else:
            None
```

Resolving patch:
diff --git a/import_export/widgets.py b/import_export/widgets.py
--- a/import_export/widgets.py
+++ b/import_export/widgets.py
@@ -7,6 +7,7 @@
 from django.utils.encoding import smart_text
 from django.utils.dateparse import parse_duration
 from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist
 
 try:
     from django.utils.encoding import force_text
@@ -343,7 +344,19 @@ def clean(self, value, row=None, *args, **kwargs):
     def render(self, value, obj=None):
         if value is None:
             return ""
-        return getattr(value, self.field)
+
+        attrs = self.field.split('__')
+        for attr in attrs:
+            try:
+                value = getattr(value, attr, None)
+            except (ValueError, ObjectDoesNotExist):
+                # needs to have a primary key value before a many-to-many
+                # relationship can be used.
+                return None
+            if value is None:
+                return None
+
+        return value
 
 
 class ManyToManyWidget(Widget):


Test patch:
diff --git a/tests/core/migrations/0007_auto_20180628_0411.py b/tests/core/migrations/0007_auto_20180628_0411.py
new file mode 100644
--- /dev/null
+++ b/tests/core/migrations/0007_auto_20180628_0411.py
@@ -0,0 +1,34 @@
+# Generated by Django 2.0.2 on 2018-06-28 04:11
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('core', '0006_auto_20171130_0147'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Person',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Role',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+        migrations.AddField(
+            model_name='person',
+            name='role',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Role'),
+        ),
+    ]
diff --git a/tests/core/models.py b/tests/core/models.py
--- a/tests/core/models.py
+++ b/tests/core/models.py
@@ -68,6 +68,14 @@ class Entry(models.Model):
     user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
 
 
+class Role(models.Model):
+    user = models.OneToOneField('auth.User', on_delete=models.CASCADE, null=True)
+
+
+class Person(models.Model):
+    role = models.ForeignKey(Role, on_delete=models.CASCADE)
+
+
 class WithDefault(models.Model):
     name = models.CharField('Default', max_length=75, blank=True,
                             default='foo_bar')
diff --git a/tests/core/tests/test_resources.py b/tests/core/tests/test_resources.py
--- a/tests/core/tests/test_resources.py
+++ b/tests/core/tests/test_resources.py
@@ -21,7 +21,7 @@
 
 from ..models import (
     Author, Book, Category, Entry, Profile, WithDefault, WithDynamicDefault,
-    WithFloatField,
+    WithFloatField, Person, Role
 )
 
 try:
@@ -935,6 +935,38 @@ def test_arrayfield(self):
             self.assertListEqual(book_with_chapters.chapters, chapters)
 
 
+class ForeignKeyWidgetFollowRelationship(TestCase):
+    def setUp(self):
+        self.user = User.objects.create(username='foo')
+        self.role = Role.objects.create(user=self.user)
+        self.person = Person.objects.create(role=self.role)
+
+    def test_export(self):
+        class MyPersonResource(resources.ModelResource):
+            role = fields.Field(
+                column_name='role',
+                attribute='role',
+                widget=widgets.ForeignKeyWidget(Role, field='user__username')
+            )
+
+            class Meta:
+                model = Person
+                fields = ['id', 'role']
+
+        resource = MyPersonResource()
+        dataset = resource.export(Person.objects.all())
+        self.assertEqual(len(dataset), 1)
+        self.assertEqual(dataset[0][0], 'foo')
+
+        self.role.user = None
+        self.role.save()
+
+        resource = MyPersonResource()
+        dataset = resource.export(Person.objects.all())
+        self.assertEqual(len(dataset), 1)
+        self.assertEqual(dataset[0][0], None)
+
+
 class ManyRelatedManagerDiffTest(TestCase):
     fixtures = ["category", "book"]