0

I'm using Django 2.2

In my application, there is a shared user feature and every shared user are added to User model with is_shared field set to True.

The shared user is linked to a user in SharedUser model like

class SharedUser(models.Model)
    user = models.ForeignKey(User, on_delete=models.CASCASE, related_name='owner_user')
    shared_user = models.ForeignKey(User, on_delete=models.CASCASE, related_name='shared_user')

On delete of a record from SharedUser model, I also have to delete the linked shared_user record from the User model. For that I'm using the post_signal receiver.

receivers.py

@receiver(post_delete, sender=SharedUser, dispatch_uid='post_delete_shared_user')
def post_delete_shared_user(sender, instance, *args, **kwargs):
    try:
        if instance and instance.shared_user:
            owner = instance.user
            instance.shared_user.delete()
    except:
        pass

and the receiver is loaded in the app.py config

class SharedUsersConfig(AppConfig):
    name = 'shared_users'

    def ready(self):
        from . import receivers

Now, whenever a record from the SharedUser model is deleted, it makes a lot of SQL queries.

enter image description here

When the import receivers is removed from the apps.py file.

enter image description here

There are a lot more SQL queries being made when the receiver is used to delete the associated user.

In my use case, there is nowhere the shared_user is associated to any other model other than SharedUser model.

  1. How can I reduce the query on deleting a user?
  2. Can I disable sending the signal when the user is deleted for this scenario only? Since a shared_user is not related to any other model.
Anuj TBE
  • 9,198
  • 27
  • 136
  • 285

1 Answers1

0

The problem is in your shared_user = models.ForeignKey(User, on_delete=models.CASCASE, related_name='shared_user') specifically the on_delete attribute.

Every time you remove a User record, all related SharedUser records gets also removed.

To prevent deletion you should use on_delete=models.SET_NULL.

Nache
  • 231
  • 1
  • 7
  • I believe `on_delete` works on associated **User** model. Means, when the user is deleted from **User** model, it will cascade the linked `shared_user`. But it doesn't work the reverse way. If it does, then disabling signal receiver won't make only 6 SQL queries. – Anuj TBE Jul 05 '19 at 13:53
  • I think that the problem there is a strange loop. Every time you remove a `SharedUser`, in a signal you remove `User` wich in cascade also remove `SharedUser` that trigger the delete signal that again remove a `User` and... loop. You have to keep in mind that a sql.DELETE is not necesary commited on model.delete() and until your record gets really deleted you will walk througt the loop. Maybe you are looking for handle commited data (https://docs.djangoproject.com/en/2.2/topics/db/transactions/#performing-actions-after-commit) – Nache Jul 05 '19 at 14:27