Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding user to group on save in Django 1.9

Tags:

Hello, I'm using Django 1.9. Trying to add a user to group on creation or save. Using either user.groups or groups.user_set.add don't work, mix and match with pre- and post-save below.

These answers aren't working for me, and so this isn't a dupe: Adding user to group on creation in Django
Adding a user to a group in django
Add users to groups in Django

I have tried both methods in both pre- and post-save handlers.

@receiver(pre_save, sender=User)
def user_presave_handler(sender, instance, **kwargs):
    if instance.is_staff and not instance.is_superuser:
        # Grant all permissions
        try:
            instance.groups.add(Group.objects.get(name='staff_user'))
        except Group.DoesNotExist:
            pass

@receiver(post_save, sender=User)
def user_postsave_handler(sender, instance, **kwargs):
    if instance.is_staff and not instance.is_superuser:
        try:
            g = Group.objects.get(name='staff_user')
        except Group.DoesNotExist:
            pass
        else:
            g.user_set.add(instance)
            g.save()

You can mix and match which method is used where, I have tried it. I don't use more than one method in testing. After hitting the save button on user admin page, the user is not shown as in the group.

I double-checked that the handlers are getting called, user logic is correct, etc.

Is there something I'm doing wrong, or something that has changed in 1.9 to break the old methods?

Thanks!

Edit: For those asking, the group is created like this:

group, __ = Group.objects.get_or_create(name='staff_user')

permissions = Permission.objects.all()
for p in permissions:
    group.permissions.add(p)
group.save()

I have debugged it and the group definitely exists, though maybe I made it wrong and so it won't be applied?

like image 704
std''OrgnlDave Avatar asked Jan 10 '17 16:01

std''OrgnlDave


2 Answers

I think it's related to this: Issue with ManyToMany Relationships not updating inmediatly after save . Somethere reports in a comment that it's still current in 1.10.

The problem is that you can also select groups on the admin 'add user' page; and then when you save the User, the following happens:

  1. The User is saved
  2. The post-save signal happens, and you add the User to the group
  3. All groups of the User are cleared
  4. The groups that were chosen on the add user page are added to the User.

You can use a m2m_changed signal, apparently. I've never used it, but I think something like this should work:

from django.db.signals import m2m_changed

@receiver(m2m_changed, sender=User.groups.through)
def user_groups_changed_handler(sender, instance, action, **kwargs):
    if action == 'post_add' and instance.is_staff and not instance.is_superuser:
        if not instance.groups.filter(name='staff_user').exists():
            try:
                g = Group.objects.get(name='staff_user')
            except Group.DoesNotExist:
               pass
            else:
                instance.groups.add(g)

This is assuming the instance that the signal receives is a User, otherwise it's going to look slightly different. The check for the action and the check whether the group was already added are to prevent infinite loops. The sender is the hidden 'through' table for the many to many relation, User.groups.through.

like image 52
RemcoGerlich Avatar answered Sep 24 '22 21:09

RemcoGerlich


Python 3, Django==2.1.7

def add_user_to_group(sender, instance: User, created: bool, **kwargs):
    try:
        if created:
            group = Group.objects.get(name=instance.user_type)
            instance.groups.add(group)
            instance.save()
    except Group.DoesNotExist:
        pass


models.signals.post_save.connect(add_user_to_group, sender=User)
like image 30
sergi0 Avatar answered Sep 24 '22 21:09

sergi0