Django UserPassesTestMixin confusion/questions?
Asked Answered
B

1

7

I am currently working on an admin dashboard, which include specific views for company administrators only which are labeled as Business users.

The app is going to have about 10 views, and I had a few questions in regards to the UserPassesTestMixin

Basically, all of my views would include this,

def test_func(self):
    return self.request.user.user_type == 'Business'

To make sure the users are Business users I am protecting the views that way.

A couple questions that I am having trouble solving on my own are:

Now with that being repeated say 10 times, is there a cleaner way to do this, rather than having def test_func in every CBV?

The other question that comes up, if the user doesn't pass test, it redirects to the login page, which I don't really like either. These views are all returning json. If the user does not pass test, I would like to just send them to something like,

JsonResponse({'message': 'Only company administrators have access to this view'})

How would I able to change that redirect only if the user does not pass test? Keeping in mind that these views also inherit from LoginRequiredMixin as well, in which if the user is not logged in I want to keep the original redirect to the login page in tact.

Any help with this is very appreciated. This side of Django is something fairly new to me!

Balmoral answered 10/12, 2020 at 19:34 Comment(0)
R
18

Now with that being repeated say 10 times, is there a cleaner way to do this, rather than having def test_func in every CBV?

Yes, you can simply make a mixin that implements the check:

from django.contrib.auth.mixins import UserPassesTestMixin

class BusinessUserMixin(LoginRequiredMixin, UserPassesTestMixin):
    
    def test_func(self):
        return self.request.user.user_type == 'Business'

    def handle_no_permission(self):
        return JsonResponse(
            {'message': 'Only company administrators have access to this view'}
        )

and then you use this mixin in your views, for example:

class MyView1(BusinessUserMixin, ListView):
    # …
    pass

class MyView2(BusinessUserMixin, DetailView):
    # …
    pass

class MyView3(BusinessUserMixin, CreateView):
    # …
    pass

if the user doesn't pass test, it redirects to the login page, which I don't really like either. These views are all returning json. If the user does not pass test, I would like to just send them to something like.

You can override the handle_no_permission method as well, the view will return the result of this method as result when the test fails.

Rae answered 10/12, 2020 at 19:40 Comment(3)
Brilliant! That is exactly what I was looking for. Thank you very, very much, once again!Balmoral
I see a problem here: you're also using LoginRequiredMixin, which also will call handle_no_permission when a user isn't authenticated, which means users that are not logged in will get your message "Only company administrators have access to this view" instead of being redirected to the login page, which is probably what you want. Am I missing something? I've seen numerous other S.O. posts that appear to confirm this assumption; both mixins call handle_no_permissions method, so you're setting a response to UserPasses... that is also going to be used for LoginRequired...Frederic
@m.arthur: well this is a JSON response, so normally used by an AJAX request that is then handled by some frontend tool like vue/react/angular.Rae

© 2022 - 2024 — McMap. All rights reserved.