24
votes

From the admin I see that you can allocate permissions to a user or a user group to :allow add, change or delete data from a model.

That is great, but I also need to allow a user or a user group to access or not a group of views. I have certain type of services on my web site so I want to allow some users to access a certain services (pages/views) but not others.

So how can I allow certain users/user groups access to certain views? Thank you!

5

5 Answers

26
votes

Users that cannot add or change etc. a certain model, will not be able to see it in the admin.

If we are talking about your custom created views then you could create something which checks a user for a permission and returns a 404 if they do not have that permission. Permissions are linked to models and a group can be assigned various permissions.

You can add a permission to a model like this:

# myproject/myapp/models.py

class MyModel(models.Model):
    class Meta:
        permissions = (
            ('permission_code', 'Friendly permission description'),
        )

Then you can check a if a user has permission like this:

@user_passes_test(lambda u: u.has_perm('myapp.permission_code'))
def some_view(request):
    # ...

Using permissions you can then easily add or remove them from users and groups simply using the admin interface.

10
votes

You need to manage that manually, but it's pretty easy. Presumably there's an attribute that determines whether or not a group has permission to see a view: then you just decorate that view with either the permission_required decorator, if it's a simple question of whether the user has a particular Permission, or user_passes_test if it's a bit more complicated:

@user_passes_test(lambda u: u.is_allowed_to_see_view_myview())
def myview(request):
    ...etc...

assuming that is_allowed_to_see_view_myview is some sort of method on the User object.

The authentication docs are pretty comprehensive.

4
votes

For class based views you can inherit UserPassesTestMixin class into the view and define test_func

from django.contrib.auth.mixins import UserPassesTestMixin

class MainView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.has_perm('app.get_main_view')

Take a look at this docs for more details on how to use this:

1
votes

Permissions system is model-centric and assumes that permissions are tied to models. I think following 2 alternatives are best options:

A. If your views are related to some specific model, use custom permissions on that model as Marcus Whybrow suggested.

B. [not tested, might not work] Subclasss User and define your own permissions there. You don't need actual model, it's just wrapper for your app's custom permission:

from django.contrib.auth.models import User
class MyUser(User):
    class Meta:
        permissions = (('can_visit_$viewset1', 'Can visit $view_set_1'))

Don't forget to run syncdb to add custom permissions to database.

1
votes

If you are using Django 1.9+, you should be able to use PermissionRequiredMixin:

For example:

from django.contrib.auth.mixins import PermissionRequiredMixin

class MainView(PermissionRequiredMixin, View):
    permission_required = 'my_services.foo_bar'
    ...

This is basically a special case of UserPassesTestMixin, designed specifically to test whether the user has the indicated permission.