Django-import-export: During import, post_save receiver is called twice

Created on 9 Feb 2020  路  6Comments  路  Source: django-import-export/django-import-export

I asked this question on SO but have had no reply so I thought I raise an issue: https://stackoverflow.com/questions/60124600/django-import-export-post-save-called-twice

I created a custom user subclassed from AbstractUser and a post_save signal and a receiver that prints the new user's id.

@receiver(post_save, sender=CustomUser, dispatch_uid='members.models.customuser.post_save')
def post_save_custom_user(sender, instance=None, created=False, **kwargs):         
    if not created:                                                                
        return                                                                     
    print('post_save_custom_user: {}'.format(instance.id))

When I create a new user via the admin interface the receiver is called once. When I import a user using django-import-export the receiver is called twice: once after the initial Submit of the import file and then again after the Confirm Import. Browsing through the code I see it creates the user in dry_run, rolls back the transaction and creates it again. But how can I tell in my receiver if it's a dry run or not?

I am using Python 3.6, Django 3.0.3, django-import-export 2.0.1

hacktoberfest

All 6 comments

I am having the same issue,
I figured maybe 'post_import' might be helpful but I don't know how to access the created data so I can do extra things with it.
Also it is called only once after import confirmation.

from import_export.signals import post_import, post_export

@receiver(post_import, dispatch_uid='balabala...')
def _post_import(model, instance, **kwargs):
    # model is the actual model instance which after import
    pass

I have also resorted to using post_import. To determine newly imported data from existing data I added a status field to the model with a default of New. Then in my receiver I look for all New records and changed the status to Imported. Then to change the status for records created manually I added this to my response_add method in admin class:

    def response_add(self, request, obj, post_url_continue=None):
        obj.status = 'Created'
        obj.save()
        return super(CustomUserAdmin, self).response_add(request, obj, post_url_continue)

i am having the same issue, I am using django-elasticsearch-dsl to index new created objects into elasticsearch, but when I use django-import-export the save post_save signal is triggering twice, so it indexes the imported row twice. Is there a way to disable signals if the import is a dry-run?

I have been hit by this as well. I wouldn't expect post_save hooks to be called until I actually click "Confirm Import".

I have described detailed issue in pr, why it happens : https://github.com/django-import-export/django-import-export/pull/1176
Use this fix, inherit below class
```py
class BaseModelResource(resources.ModelResource):
save_points = []

def before_save_instance(self, instance, using_transactions, dry_run):
    """
    Override to add additional logic. Does nothing by default.
    Saving intermediate savepoints of txn
    """
    if using_transactions and dry_run:
        con = transaction.get_connection()
        self.save_points.extend(con.savepoint_ids)

def after_import(self, dataset, result, using_transactions, dry_run, **kwargs):
    """
    Override to add additional logic. Does nothing by default.
    Manually removing commit hooks for intermediate savepoints of atomic transaction
    """
    if using_transactions and dry_run:
        con = transaction.get_connection()
        for sid in self.save_points:
            con.run_on_commit = [
                (sids, func) for (sids, func) in con.run_on_commit if sid not in sids
            ]
    super().after_import(dataset, result, using_transactions, dry_run, **kwargs)

I was recently hit by something similar to this issue and I solved it by doing something this like this https://stackoverflow.com/a/33192224/5779280 . Would adding a temporary value to the instance be a solution to this problem?

I admit its not an elegant solution, but I think it would work and should be quite simple to add to the package.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cesardft picture cesardft  路  5Comments

lmeroc picture lmeroc  路  3Comments

ShaheedHaque picture ShaheedHaque  路  3Comments

s-y picture s-y  路  6Comments

leotop picture leotop  路  6Comments