Search code examples
pythondjangouser-profiledjango-permissions

Django- how to add user profile permissions based for selected users


In my Django app, I have a user_profile model (below). Each user has an is_adm boolean value:

user_profile/models.py:

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField('username', max_length=50, unique=True)
    email = models.EmailField('email address', unique=True)
    first_name = models.CharField(max_length=20, blank=True, null=True)
    last_name = models.CharField(max_length=20, blank=True, null=True)
    is_adm = models.BooleanField(default=False)

Separately I have a posts model for blog posts. There is an admin panel for this model where you can add a new Post instance. You can also update, delete or view other Post instances there.

posts/models.py:

class Posts(models.Model):
    title = models.CharField(max_length=300, default='')
    publish_date = models.DateField(blank=True, null=True)
    author = models.CharField(max_length=300)
    copy = models.TextField(blank=True, default='')
    link = models.URLField(blank=True)
    source = models.TextField(default='', blank=True)
    published = models.BooleanField(default=False)

I want the ability for is_adm = True users to be able to:

  • add a Post model instance in the admin panel
  • delete any Post model instance in the admin panel
  • view any Post model instance in the admin panel
  • edit fields in the Posts admin panel

I know that Django has Permissions and Authorization: https://docs.djangoproject.com/en/2.2/topics/auth/default/#permissions-and-authorization

But how do I add these methods like: has_view_permission(), has_add_permission(), has_change_permission() and has_delete_permission()...

... for is_adm = True users so that they can add, delete, view and change Post model instances through the Post admin panel?


Solution

  • I propose you two solutions. I am sure about the first one because I use it on a personal project. However, I never tested the second one.

    Create Admin Manager

    You can create a specific admin manager for your Posts model and override the methods which manage the permissions.

    The following code gives all permissions if the user of the request has is_adm to True, otherwise it gives the default permission value.

    from django.contrib.admin import ModelAdmin, register
    
    @register(Posts)
    class PostsAdmin(ModelAdmin):
        def has_add_permission(self, request):
            if request.user.is_adm:
                return True
            return super().has_add_permission(request)
    
        def has_view_permission(self, request, obj):
            if request.user.is_adm:
                return True
            return super().has_view_permission(request, obj)
    
        def has_change_permission(self, request, obj):
            if request.user.is_adm:
                return True
            return super().has_change_permission(request, obj)
    
        def has_delete_permission(self, request, obj):
            if request.user.is_adm:
                return True
            return super().has_delete_permission(request, obj)
    

    Modify your User

    An other solution could be to override the has_perm method of your custom User which is inherits from PermissionsMixin.

    The following code should give all permissions if the user has is_adm to True and the object is an instance of Posts.

    class User(AbstractBaseUser, PermissionsMixin):
        username = models.CharField('username', max_length=50, unique=True)
        email = models.EmailField('email address', unique=True)
        first_name = models.CharField(max_length=20, blank=True, null=True)
        last_name = models.CharField(max_length=20, blank=True, null=True)
        is_adm = models.BooleanField(default=False)
    
        def has_perm(self, perm, obj=None):
            if self.is_adm and isinstance(obj, Posts):
                return True
            return super().has_perm(perm, obj)