How to do something after a Django user model save, including related changes to m2m fields like django.contrib.auth.models.Group
?
Situation
I have a custom Django user model and want to trigger some actions after a user instance is - with related changes such as m2m group memberships - successfully saved to the database.
The use case here is a Wagtail CMS where I create ProfilePage
s for each user instance. Depending of the group memberships of the user instance, I need to do something.
Problem
In a custom model save()
method, I'm not able to reference the changed group memberships, as m2m's are saved after the saving of the user instance. Even if running my custom function after the super().save()
call, new group memberships are not yet available.
But I need to get the new group memberships in order to do something depending of the new groups for that user.
What I've tried
[✘] Custom model save()
# file: users/models.py
class CustomUser(AbstractUser):
super().save(*args, **kwargs)
do_something()
[✘] Signal post_save
As the above simple save() method did not do the trick, I tried the post_save
signal of the user model:
# file users/signals.py
@receiver(post_save, sender=get_user_model())
def handle_profilepage(sender, instance, created, **kwargs):
action = 'created' if created else 'updated'
do_something()
... but even here I always get the "old" values from the group membership back.
[✔] Signal: m2m_changed
I learnt that there is a m2m_changed
signal with which I could monitor changes of the Users.groups(.through)
table.
My following implementation did what I need:
@receiver(m2m_changed, sender=User.groups.through)
def user_groups_changed_handler(sender, instance, **kwargs):
USER_GROUPS = instance.groups.values_list('name', flat=True)
if set(USER_GROUPS) & set(settings.PROFILE_GROUPS):
do_something_because_some_groups_match()
else:
do_something_else()
My whishlist
I would happily stay away from signals if there is a chance to solve this problem in the models save()
method - but I'm stuck...