Search code examples
pythondjangodjango-admindjango-users

Add user to permission group when creating user in Django Admin


I would to add a User to a permission group automatically when create a User. I have hear about user.groups.add(group) and group.user_set.add(user). But it doesn't work. My final purpose is to have 3 kind of users:

  1. SuperAdmin: One superadmin to manage the site.
  2. Administrators: User administrators. Which can manage regular users. Upload photos, add new Users to manage, etc.
  3. Regular Users: The normal users which will use the aplicación. They don't have any permission, just login the site, but not the adminSite.

MODELS.PY

from django.db import models
from django.contrib.auth.models import AbstractUser, Group
from django.db.models.signals import post_save
from django.dispatch import receiver


# Create your models here.

class MyUser(AbstractUser):
    descripcion = models.TextField(blank=True)
    telefono = models.PositiveSmallIntegerField(default=000)
    avatar = models.ImageField(upload_to='users/avatar/', blank=True)

    def __str__(self):
        return self.username


class RegularUser(MyUser):
    MyUser.is_staff = False
    MyUser.is_superuser = False

    class Meta:
        verbose_name = 'Usuario Regular'
        verbose_name_plural = 'Usuarios Regulares'


class AdminUser(MyUser):
    usuarios = models.ManyToManyField(RegularUser, help_text="Selecciona los usuarios que administra")
    MyUser.is_staff = True

    class Meta:
        verbose_name = 'Administrador'
        verbose_name_plural = 'Adminsitradores'

ADMIN.PY

from django.contrib import admin
from django import forms
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.models import Group

from myApp.models import MyUser, RegularUser, AdminUser


# Register your models here.


class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required fields,
     plus a repeated password"""
    password1 = forms.CharField(label='Contraseña', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repita Contraseña',
                                widget=forms.PasswordInput)

    class Meta:
        model = MyUser
        fields = ('email',
                  'first_name',
                  'last_name',
                  'telefono',
                  'avatar',
                  'groups',)

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Las contraseñas no coinciden")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on the user
    , but replaces the password field with admin's password
    hash display field"""

    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('username',
                  'email',
                  'password',
                  'first_name',
                  'last_name',
                  'descripcion',
                  'telefono',
                  'avatar',
                  )

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


class AdminCreationForm(forms.ModelForm):
    """A form for creating new Admin users. Including all required fields,
    plus a repeated password"""
    password1 = forms.CharField(label='Contraseña', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repita Contraseña', widget=forms.PasswordInput)

    # usuarios = forms.CharField(label= 'Usuarios', widget=forms.SelectMultiple(choices=RegularUser.objects.all()))

    class Meta:
        model = AdminUser
        fields = ('username',
                  'email',
                  'password',
                  'telefono',
                  'avatar',
                  'usuarios',
                  'groups',)

    def clean_password2(self):
        # Check that the 2 password entries match
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2 and password1 != password2:
            raise ValueError("Las contraseñas no coinciden")
        return password2

    # def _save_m2m(self):
    #     user = super().save(commit=False)
    #     self.instance.user_set = self.cleaned_data['user']

    def save(self, commit=True):
        # Save the commit password in hashed form
        user = super().save(commit=False)
        user.set_password(self.cleaned_data['password1'])
        # Set the current User as admin user
        user.is_staff = True

        if commit:
            user.save()
            group = Group.objects.get(name="Administradores")
            user.groups.add(group)
            # group.user_set.add(user)
            # group.save()
        return user

    @receiver(post_save, sender=AdminUser)
    def post_save_admin(sender, instance, **kwargs):
        if kwargs['created'] and instance.is_staff:
            grupo = Group.objects.get(name="Administradores")
            grupo.user_set.add(instance)


class AdminChangeForm(forms.ModelForm):
    """ A form for updating Administrators. Includes all the fields on the user
    , but replaces the password field with admin's password hash display field"""

    password = ReadOnlyPasswordHashField()

    class Meta:
        model = AdminUser
        fields = ('username',
                  'email',
                  'password',
                  'first_name',
                  'last_name',
                  'descripcion',
                  'telefono',
                  'avatar',
                  'usuarios',
                  'groups',
                  )

    def clean_password(self):
        # Regardless of what the admin provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


class AdminUserAdmin(BaseUserAdmin):
    # The forms to add and change admin instances
    form = AdminChangeForm
    add_form = AdminCreationForm

    # The fields to be used in displaying the Admin model.
    # These overrides the definitions on the base AdminUserAdmin
    # that reference specific fields on auth.User
    list_display = ('username', 'email',)
    list_filter = ('last_login',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Información Personal', {'fields': ('first_name', 'last_name', 'descripcion', 'avatar', 'telefono',)}),
        ('Administración', {'fields': ('is_staff', 'usuarios','groups')}),
    )
    # add_fieldsets is not a standard Modeladmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'email', 'telefono', 'password1', 'password2', 'usuarios','groups')}
         ),
    )
    search_fields = ('username',)
    ordering = ('username',)
    filter_horizontal = ()



class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('username', 'email', 'is_staff')
    list_filter = ('is_staff',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('first_name', 'last_name', 'descripcion', 'avatar', 'telefono',)}),
        ('Permissions', {'fields': ('is_staff', 'is_superuser')}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'email', 'telefono', 'password1', 'password2',)}
         ),
    )
    search_fields = ('username',)
    ordering = ('username',)
    filter_horizontal = ()

    # Now register the new UserAdmin...


admin.site.register(MyUser, UserAdmin)

admin.site.register(AdminUser, AdminUserAdmin)


# @admin.register(MyUser)
# class MyUserAdmin(admin.ModelAdmin):
#     pass


# @admin.register(AdminUser)
# class AdminUserAdmin(admin.ModelAdmin):
#     # The forms to add and change Admin instances:
#     form = AdminChangeForm


@admin.register(RegularUser)
class RegularUserAdmin(admin.ModelAdmin):
    pass

I think the solution must be here, but it doesn't work:

SAVE USER FUNCTION

def save(self, commit=True):
        # Save the commit password in hashed form
        user = super().save(commit=False)
        user.set_password(self.cleaned_data['password1'])
        # Set the current User as admin user
        user.is_staff = True

        if commit:
            user.save()
            group = Group.objects.get(name="Administradores")
            user.groups.add(group)
            # group.user_set.add(user)
            # group.save()
        return user

Solution

  • This is the solution I have found.

    @receiver(post_save, sender= AdminUser)
    def add_admin_permission(sender, instance, created, **kwargs):
        if created:
            grupo = Group.objects.get(id=1)
            grupo.user_set.add(instance)