Home > Mobile >  How add user to a group when update and create a user
How add user to a group when update and create a user

Time:04-29

I created a bunch of groups fallowing this link: https://stackoverflow.com/questions/22250352/programmatically-create-a-django-group-with-permissions#:~:text I subscribed the User class adding a choice field called "role". Basically, that means what role that user has. That way if a user has the role of "staff" . Thus It'll have permissions of the group staff. The problem is: I can't get django to respond the way I expected. I put a signal after saving that it should add the user to the group according to their role. The program looks like this:

# project/app/model.py

class User(AbstractUser):
    class Roles(models.IntegerChoices):
        SUPER = 0, _('SuperAdmins')
        COMPANY = 1, _('Company')
        UNITY = 2, _('Unity')
        STAFF = 3, _('Staff')

   role: Roles = models.IntegerField(choices=Roles.choices, default=Roles.STAFF, verbose_name=_("Role"))

My signal is like:

GROUPS = ['SuperAdmins', 'Company', 'Unity', 'Staff']
@receiver(post_save, sender=User)
def user(sender: User, instance: User, created: bool, **kwargs) -> None:
    """
    This receiver function will set every staff pages that is created to the group staff.

    :param sender: the model that will trigger this receiver
    :param instance: the instance
    :param created: if it was already created
    :param kwargs:
    :return: None
    """
    if created:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.add(group)
    else:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.add(group)
        print("update")

When I go to the admin page and I create a new user, everything works as expected. But when I edit the role of an existing user, it just prints the "update" fron the print function but nothing changes. What am I doing wrong?

CodePudding user response:

With your current code, when changing the user role it will be added to a new group (without being removed from the previous one). For example if the user is part of the group Staff initially and then its role changes to Company it will be added to the Company group. As the relationship between the User model and the Group model is a Many to Many relationship, the user won't be removed from the Staff group. To do that there are to ways (which are basically the same):

First option with clear then add:

if created:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.add(group)
    else:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.clear() # Dissasociates any group the user belonged to
        instance.groups.add(group) # Adds the group

Second option with set:

if created:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.add(group)
    else:
        group = Group.objects.get(name=GROUPS[instance.role])
        instance.groups.set([group], clear=True) # Dissasociates any group the user belonged to and sets the new group. clear=True is necessary here because otherwise the Group instances would be deleted

With all this, if you decide to go with the second option, you can go with set also for users that are being created:

GROUPS = ['SuperAdmins', 'Company', 'Unity', 'Staff']
@receiver(post_save, sender=User)
def user(sender: User, instance: User, **kwargs) -> None:
    """
    This receiver function will set every staff pages that is created to the group staff.

    :param sender: the model that will trigger this receiver
    :param instance: the instance
    :param kwargs:
    :return: None
    """
    group = Group.objects.get(name=GROUPS[instance.role])
    instance.groups.set([group], clear=True)

and thus you don't have to use the created param. For more info on clear and set you can read the docs https://docs.djangoproject.com/en/4.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.clear and see how they can be used!

CodePudding user response:

I'll post the solution here in case anyone encounters the same problem. Along with the contribution of @mtzd. I found a tip for the solution based on the description of a problem that was in this post: https://stackoverflow.com/a/1925784/18600263. So the pos_save signal will be:

from django.db import transaction

GROUPS = ['SuperAdmins', 'Company', 'Unity', 'Staff']


@receiver(post_save, sender=User)
def user(sender: User, instance: User, **kwargs) -> None:
    group = Group.objects.get(name=GROUPS[instance.role])
    transaction.on_commit(lambda: instance.groups.set([group], clear=True))
  • Related