Home > Back-end >  django UserPassesTestMixin with parameter
django UserPassesTestMixin with parameter

Time:03-21

Here's working version with user_passes_test. But I would like to replace position > 1 with parameter. I found that, it's possible to do with UserPassesTestMixin. But I don't know how. Can anyone help?

models.py

class user_control(models.Model):
    user = models.ForeignKey(user, on_delete=CASCADE)    
    position = models.ForeignKey(position, on_delete=CASCADE)
    ...

views.py

def position_check(user):    
    position = 0 if user.is_anonymous else user_control.objects.values(
            'position__rank'
        ).get(
            user = user.id        
        )

    return True if position > 1 else False

@user_passes_test(position_check, login_url='loginPage')
def index(request):
   pass

@user_passes_test(position_check, login_url='loginPage')
def exportReview(request):
   pass

I was try:

class PositionCheckMixin(LoginRequiredMixin, UserPassesTestMixin):
    position_value = 2    

    def test_func(self):
        position = 0 if user.is_anonymous else user_control.objects.values(
                'position__rank'
            ).get(
                user = self.request.user.id        
            )
    
        return position > self.position_value

    def handle_no_permission(self):
        return redirect('loginPage')
    
class Review(PositionCheckMixin):
   position_value = 2

   def index(request):

CodePudding user response:

You can make a decorator that takes for example an optional parameter:

def position_check(function=None, position_value=1, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
    def check(user):    
        position = 0 if user.is_anonymous else user_control.objects.values(
            'position__rank'
        ).get(
            user=user.id        
        )
        return position > position_value
    
    actual_decorator = user_passes_test(
        check,
        login_url=login_url,
        redirect_field_name=redirect_field_name,
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

Then you can use the decorator with:

@position_check(position_value=42, login_url='loginPage')
def index(request):
    # …
    pass

For a class-based view, using the UserPassesTestMixin mixin [Django-doc] is more convenient:

class PositionCheckMixin(UserPassesTestMixin):
    position_value = 1
    
    def test_func(self):
        position = 0 if self.request.user.is_anonymous else user_control.objects.values(
            'position__rank'
        ).get(
            user=self.request.user.id
        )

        return position > self.position_value

then you can mix this in a class-based view with:

class MyView(PositionCheckMixin, View):
    position_value = 42
    
    # …
  • Related