J.Cleese
J.Cleese

Reputation: 35

Group permission connected to model list

My model:

class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)

POSITIONS = (
    ("volunteer", "volunteer"),
    ("employee", "employee"),
    ("manager", "manager"),
    ("director", "director"),
    ("vet", "vet")
)
position = models.CharField(choices=POSITIONS, max_length=15)
picture = models.ImageField(blank=True, null=True)

And I am using class based views. I want to make a permissions to access diffrent views depending to 'position' value. I have found dozen of solutions and now I am a bit confused. What is the best way to make what I want to do?

Upvotes: 1

Views: 55

Answers (1)

Mitchell Walls
Mitchell Walls

Reputation: 1151

I would use custom decorators. You can use the @method_decorator(decorator, name='dispatch'). First you would create a decorators.py file in the app directory. Pretty much what happens is the method decorator is called before the view and passes the function to the first callable. What we actually do is we make the callable callable as position check and pass the position argument. Then we process the actual method decorator part which passes the function argument in _method_wrapper. At which point, we do our calculations just like we would in the view with the request variable in the _wrapper callable.

# decorators.py
from django.core.exceptions import PermissionDenied
from app.models import UserProfile

def position_check(position):
    def _method_wrapper(function):
        def _wrapper(request, *args, **kwargs):
            try:
                user = UserProfile.object.get(user_id=request.user.id)
            except UserProfile.DoesNotExist:
                raise PermissionDenied
            if user.position == position:
                return function(request, *args, **kwargs)
            else:
                raise PermissionDenied
        return _wrapper
    return _method_wrapper

Now in your view you would call it like this.

# views.py
from app.decorators import position_check
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(position_check('manager'), name='dispatch')
class HomeView(TemplateView):
    template_name = "home.html"

The only issue I could see you running into is needing to inherit permissions. I wouldn't set your choices up the way you have them. I would set the actual value to a number and the choice portion to your human readable such as below. This would allow you to set permissions contingent upon the number value so if user.position >= 3 a director would then inherit permissions from manager.

POSITIONS = (
    (1, "volunteer"),
    (2, "employee"),
    (3, "manager"),
    (4, "director"),
    (5, "vet")
)

Upvotes: 1

Related Questions