View access based on group membership


I wanted to restrict access to views based on the users membership to group. I have used the @user_passes_test decorator testing to see if a user belongs to a group. However, to do this I have to create a function that filters for each group to later use in the decorator. This is because when the test function is within the decorator I cant pass a list with the groups that should get access. Is there another approach to this? Also how would this work in class based views?

Example of function used in decorator:

def op1_user(user):
    if user.groups is None:
        return False
    return user.groups.filter(name="OP1").exists()


Hey there!
Can you explain a bit more about your need?
Do you need to filter for more than one group?
Do you need to filter for a specific group name, but don’t want to create a function to each one of it?

Yes I would like to filter for one or more groups and not create a function for each case.

Right, so one approach is a “decorator factory”.
A decorator factory is a function that creates the decorator function.
It looks like this.

def is_on_group_check(*groups):
  def on_group_check(user):
     if user.groups is None:
       return False
     return user.groups.filter(name__in=groups).exists()

  return on_group_check

Then, you can create a decorator for each group of groups you need, like:

on_op1_group = is_on_group_check("OP1")
on_op1_to_3_groups = is_on_group_check("OP1", "OP2", "OP3")

Then you will use the created decorators on the user_passes_test decorator.

def your_view(request):

How could it be done for class based views?

Actually, what I would say here is that this is entirely the wrong approach.

I would suggest that the “best Django process” is to use the built-in permission system rather than group level checks. It’s a lot more flexible and easier to administer.

Briefly, you define or identify a permission that is needed for each view, then assign that permission to all groups that need it. Then you use one of the permission tests to check to see if that user is allowed to access that view.

The concept is referred to as “Role-based security” and is a common pattern beyond Django. If you search through the forum, you can find other posts where this has been discussed in more detail.

1 Like

Are permissions created per model not per view?

Permissions are created however you want them to be.

The system (by default) creates a set of permissions for each model created by Migrations.

How you create permissions is up to you.

How can they be created by view? Custom permissions are created around models as well …

My issue is I never see how permissions can be custom made to relate with views the documentation always seems to relate these more closely to models.

You’ve come to a “reasonable, but inaccurate” conclusion from the documentation.

Please read the full thread at Conditional content rendering, based on permissions

Yes I think I have the same issues as those reflected in the thread. After reading this I have the following question, how can I attach the permissions to the users that are show in the django admin?(Where is the class definition in which under the meta tag I can add the necessary permissions)

I’m sorry, I don’t understand what you’re trying to ask here.

If the permissions have to be added to some class that should be the user class used in the django admin(modify the meta of such class to contain the permissions). Is that the correct approach? As shown here Managing User Permissions in Django - Honeybadger Developer Blog.

The permissions do not need to be added to a class.

An instance of the Permission model can be created with a reference to a class.

See Programmatically creating permissions

1 Like

Do your views not present Models to your users? Would maybe the permission fit to the most prominent on a view?

If not, you could create a “permission” app with one empty model that just holds permissions. This is something I have done in the past, although I would probably not do this again. But it works and you don’t have to think about how you programmatically add permissions that should be in your project by default.