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

Issue:
Hooking admin EntryLog to after_save_instance
I would like to add something like this to an overridden Resource.after_save_instance function to keep LogEntry consistent:

```
class ExampleResource(resources.ModelResource):
    def after_save_instance(self, instance, dry_run):
        from django.contrib.admin.models import LogEntry, ADDITION
        LogEntry.objects.log_action(
            user_id=request.user.pk,
            content_type_id=ContentType.objects.geggt_for_model(object).pk,
            object_id=object.pk,
            object_repr=force_text(object),
            action_flag=ADDITION
        )
```

Problem is that I don't have access to request from there. Don't know if it is a good idea to pass it on from ImportMixin or that you want to keep request logic out of resources.py?  Another way would be to override process_import in ImportMixin and use the result returned by resouce.import_data to update LogEntry. Any thoughts on that?



Discussion:
[RowResult](https://github.com/bmihelac/django-import-export/blob/master/import_export/results.py#L11) is populated and returned as `import_data` result with useful information that can be added to `LogEntry`.

`RowResult`  however misses crucial information, `pk` of added/updated/deleted object - this should not be hard to add and then in `ImportMixin. process_import` can loop through results and add log entries. 

What do you think?

Yes, extending RowResult would be great! Then one would only have to override process_import

do you want to write a patch?

p.s. I think this this is expected behaviour and could be added to `process_import` without need for overriding

Sure! I'll give it a shot.


Resolving patch:
diff --git a/import_export/admin.py b/import_export/admin.py
--- a/import_export/admin.py
+++ b/import_export/admin.py
@@ -9,6 +9,8 @@
 from django.conf.urls import patterns, url
 from django.template.response import TemplateResponse
 from django.contrib import messages
+from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
+from django.contrib.contenttypes.models import ContentType
 from django.http import HttpResponseRedirect, HttpResponse
 from django.core.urlresolvers import reverse
 
@@ -21,6 +23,7 @@
     modelresource_factory,
 )
 from .formats import base_formats
+from .results import RowResult
 
 try:
     from django.utils.encoding import force_text
@@ -112,9 +115,26 @@ def process_import(self, request, *args, **kwargs):
                 data = force_text(data, self.from_encoding)
             dataset = input_format.create_dataset(data)
 
-            resource.import_data(dataset, dry_run=False,
+            result = resource.import_data(dataset, dry_run=False,
                                  raise_errors=True)
 
+            # Add imported objects to LogEntry
+            logentry_map = {
+                RowResult.IMPORT_TYPE_NEW: ADDITION,
+                RowResult.IMPORT_TYPE_UPDATE: CHANGE,
+                RowResult.IMPORT_TYPE_DELETE: DELETION,
+            }
+            content_type_id=ContentType.objects.get_for_model(self.model).pk
+            for row in result:
+                LogEntry.objects.log_action(
+                    user_id=request.user.pk,
+                    content_type_id=content_type_id,
+                    object_id=row.object_id,
+                    object_repr=row.object_repr,
+                    action_flag=logentry_map[row.import_type],
+                    change_message="%s through import_export" % row.import_type,
+                )
+
             success_message = _('Import finished')
             messages.success(request, success_message)
             import_file.close()
diff --git a/import_export/resources.py b/import_export/resources.py
--- a/import_export/resources.py
+++ b/import_export/resources.py
@@ -338,6 +338,9 @@ def import_data(self, dataset, dry_run=False, raise_errors=False,
                     else:
                         self.save_instance(instance, real_dry_run)
                         self.save_m2m(instance, row, real_dry_run)
+                        # Add object info to RowResult for LogEntry
+                        row_result.object_repr = str(instance)
+                        row_result.object_id = instance.pk
                     row_result.diff = self.get_diff(original, instance,
                             real_dry_run)
             except Exception as e:
diff --git a/import_export/results.py b/import_export/results.py
--- a/import_export/results.py
+++ b/import_export/results.py
@@ -33,3 +33,6 @@ def row_errors(self):
 
     def has_errors(self):
         return bool(self.base_errors or self.row_errors())
+
+    def __iter__(self):
+        return iter(self.rows)


Test patch:
diff --git a/tests/core/tests/admin_integration_tests.py b/tests/core/tests/admin_integration_tests.py
--- a/tests/core/tests/admin_integration_tests.py
+++ b/tests/core/tests/admin_integration_tests.py
@@ -5,6 +5,7 @@
 from django.test.testcases import TestCase
 from django.contrib.auth.models import User
 from django.utils.translation import ugettext_lazy as _
+from django.contrib.admin.models import LogEntry
 
 from core.admin import BookAdmin
 
@@ -86,3 +87,26 @@ def test_import_file_name_in_tempdir(self):
         }
         with self.assertRaises(IOError):
             self.client.post('/admin/core/book/process_import/', data)
+
+    def test_import_log_entry(self):
+        input_format = '0'
+        filename = os.path.join(
+            os.path.dirname(__file__),
+            os.path.pardir,
+            'exports',
+            'books.csv')
+        with open(filename, "rb") as f:
+            data = {
+                'input_format': input_format,
+                'import_file': f,
+            }
+            response = self.client.post('/admin/core/book/import/', data)
+        self.assertEqual(response.status_code, 200)
+        confirm_form = response.context['confirm_form']
+        data = confirm_form.initial
+        response = self.client.post('/admin/core/book/process_import/', data,
+                follow=True)
+        self.assertEqual(response.status_code, 200)
+        book = LogEntry.objects.latest('id')
+        self.assertEqual(book.object_repr, "Some book")
+        self.assertEqual(book.object_id, str(1))