How do I raise PermissionDenied Redirect to another page using CBV?

Viewed 4992

I have a model with my permissions, and in my view using CBV(generic.CreateView) or (generic.DetailView), if a user logged has permissions, he can access the view, if hasn't access, the page Forbidden 403 shows.

But, if a user dont have permission for that view, I want raise exception PermissionDenied, and redirect to a specific page for this error.

My view:

class AddJob(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView)

   permission required = 'can_create_job'
   model = Job
   fields = ['name', 'description', 'salary']
   success_url = reversy_lazy('job_list)
   context_object_name = 'object_name'

Can anyone help me? Thanks

3 Answers

First of all, you can't do both redirection and raise 404 exception.

That is, you could either redirect to some page if the user has no permission or raise an exception.

Case 1 : raise an exception
to raise the exception, you should add raise_exception = True in your view class as,

class AddJob(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView):
    permission_required = 'can_create_job'
    model = Job
    fields = ['name', 'description', 'salary']
    success_url = reversy_lazy('job_list')
    context_object_name = 'object_name'
    raise_exception = True # Change is here

Case 2 : redirect to specific page
Set login_url in your view,

class AddJob(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView):
    permission_required = 'can_create_job'
    model = Job
    fields = ['name', 'description', 'salary']
    success_url = reversy_lazy('job_list')
    context_object_name = 'object_name'
    login_url = '/path/to/specific/page'



What will happen if you set both login_url and raise_exception ?

The AccessMixin class has a method handle_no_permission() which is being called to handle this condition.

Source Code

def handle_no_permission(self):
    if self.raise_exception:
        raise PermissionDenied(self.get_permission_denied_message())
    return redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())

Here you can see, if you set raise_exception = True, django won't consider the login_url

Lots of things addressed here, but just thought I'd add some options:

I you want full control in some standardized way for different views, you can create your own mixing by subclassing Django's:

class MyAccessMixin(AccessMixin):
    """ A custom AccessMixing to handle access denied from PermissionRequired """
    permission_denied_message = "Oupsies! You do not have access!"

    def handle_no_permission(self):
        messages.info(self.request ,self.permission_denied_message)
        # or specific redirects based on context 
        return redirect(reverse_lazy(self.my_perm_denied_url_string))

Assuming the url you redirect to displays messages from the framework, it'll show to users.

And of course you'd add the mixin to your views, e.g.:

class AddJob(LoginRequiredMixin, PermissionRequiredMixin, MyAccessMixin, generic.CreateView):
    # code
Related