[Fixed]-How can make Django permission_required decorator not to redirect already logged-in users to login page, but display some message

12👍

A quick and dirty solution would be to write your own decorator to do this. Something like this:

decorator_with_arguments = lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)

@decorator_with_arguments
def custom_permission_required(function, perm):
    def _function(request, *args, **kwargs):
        if request.user.has_perm(perm):
            return function(request, *args, **kwargs)
        else:
            request.user.message_set.create(message = "What are you doing here?!")
            # Return a response or redirect to referrer or some page of your choice
    return _function

You can then decorate your view thus:

@custom_permission_required('my_perm')
def my_view(request, *args, **kwargs):
    #Do stuff

12👍

Since django 1.4 permission_required has a raise_exception parameter that you can set to True to have an unauthorized PermissionDenied exception raised

Eg. to give an exemple on a Class Based View:

from django.contrib.auth.decorators import permission_required
...

class MyView(TemplateView):

    @method_decorator(permission_required('can_do_something', raise_exception=True))
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

Ref:permission_required decorator doc

1👍

You can write your own decorator to replace django’s permission_required decorator:

from django.utils import six
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import user_passes_test

def permission_required(perm, login_url=None, raise_exception=True):
    def check_perms(user):
        if isinstance(perm, six.string_types):
            perms = (perm, )
        else:
            perms = perm
        if user.has_perms(perms):
            return True
        if raise_exception and user.pk:
            raise PermissionDenied
        return False
    return user_passes_test(check_perms, login_url=login_url)

And use it the same way:

@permission_required('app.permission')
def view_page(request):
    # your view function

Logged in users with no permission will get a 403 forbidden error. Those who are not logged in will be redirected to the login page.

👤Lidor

1👍

I’m assuming this question requires two pieces

  • Users that are already logged in do not get redirected to the login page
  • Users that are not logged in do not get redirected

@Manoj Govindan’s answer nor @Stefano’s answer will not work. @Lidor’s answer will work, but he has fully re-implemented the permission_required function.

Here is a simpler way:

@login_required
@permission_required('hi there', raise_exception=True)
def blah(request):
    pass

With this, if the user is not logged in, they will be redirected. If they are but they don’t have permissions, they will be down an error.

1👍

I had the same problem but learned about raise_exception parameter at the @permission_required decorator!
this parameter is False by default, but once you pass it the True value, it will automatically redirect the without permission user to the 403.html page! (if there was any 403.html page in the root of your project, otherwise shows the server 403 forbidden page!
read more in Django docs here

@permission_required('app_name.view_model', raise_exception=True)
    def some_model_view(request):
        ...

0👍

You can add a parameter "login_url" to the decorator:

@permission_required("my_app.add_user", login_url="url_name")
👤Ori.B

Leave a comment