Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use LoginRequiredMixin and UserPassesTestMixin at the same time

I want to have a TemplateView Class that uses LoginRequiredMixin and UserPassesTestMixin at the same time. Something like this:

from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

class FinanceOverview(LoginRequiredMixin, UserPassesTestMixin, TemplateMixin):
    login_url = '/login'
    redirect_field_name = 'next'

    def test_func(self):
        return self.request.user.groups.filter(name="FinanceGrp").exists()

    def get(self, request, *args, **kwargs):
        DO SOMETHING IF USER IS AUTHENTICATED AND ALSO MEMBER OF GROUP FinanceGrp

Basically as you can see above, what I want to achieve is the following:

  • If user is not authenticated, to redirect user to:

    https://website/login?next=financeoverview 
    
  • However what I can't figure out is how to redirect users who are authenticated but do not belong to group FinanceGrp to another page. For example:

    https://website.com/access_denied?previous_page=financeoverview
    

In my case users are always redirected to /login page when they fail the group test. How can I achieve two mixins used at the same time but at the same time both of them are clashing around variable login_url. Unfortunately UserPassesTestMixin is using the same login_url so it makes this trouble for me.

Thanks in advance

Milos

like image 404
Milos Kostic-Veljkovic Avatar asked Nov 03 '17 11:11

Milos Kostic-Veljkovic


2 Answers

I think you're better off subclassing AccessMixin and then performing these checks yourself. Something like this:

from django.contrib.auth.mixins import AccessMixin
from django.http import HttpResponseRedirect 

class FinanceOverview(AccessMixin, TemplateMixin):

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            # This will redirect to the login view
            return self.handle_no_permission()
        if not self.request.user.groups.filter(name="FinanceGrp").exists():
            # Redirect the user to somewhere else - add your URL here
            return HttpResponseRedirect(...)

        # Checks pass, let http method handlers process the request
        return super().dispatch(request, *args, **kwargs)
like image 67
solarissmoke Avatar answered Sep 20 '22 14:09

solarissmoke


You should override get_login_url:

class FinanceOverview(LoginRequiredMixin, UserPassesTestMixin, TemplateMixin):
    login_url = '/login'
    redirect_field_name = 'next'

    def test_func(self):
        return self.request.user.groups.filter(name="FinanceGrp").exists()

    def get_login_url(self):
        if self.request.user.is_authenticated:
            return URL_FOR_AUTHENTICATED_USERS
        return super().get_login_url()

    def get(self, request, *args, **kwargs):
        DO SOMETHING IF USER IS AUTHENTICATED AND ALSO MEMBER OF GROUP FinanceGrp
like image 22
A K Avatar answered Sep 18 '22 14:09

A K