Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the user_passes_test decorator in class based views?

I am trying to check certain conditions before the user is allowed to see a particular user settings page. I am trying to achieve this using the user_passes_test decorator. The function sits in a class based view as follows. I am using method decorator to decorate the get_initial function in the view.

class UserSettingsView(LoginRequiredMixin, FormView):
    success_url = '.'
    template_name = 'accts/usersettings.html'

    def get_form_class(self):
        if self.request.user.profile.is_student:
            return form1
        if self.request.user.profile.is_teacher:
            return form2
        if self.request.user.profile.is_parent:
            return form3

    @method_decorator(user_passes_test(test_settings, login_url='/accounts/usertype/'))
    def get_initial(self):
        if self.request.user.is_authenticated():
            user_obj = get_user_model().objects.get(email=self.request.user.email)
            if user_obj.profile.is_student:
                return { ..........
       ...... .... 

Below is the test_settings function:

def test_settings(user):
    print "I am in test settings"
    if not (user.profile.is_student or user.profile.is_parent or user.profile.is_teacher):
        return False
    else:
        return True

I am getting the below error with the decorator.

File "../django/core/handlers/base.py", line 111, in get_response
  response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "../django/views/generic/base.py", line 69, in view
  return self.dispatch(request, *args, **kwargs)
File "../braces/views.py", line 107, in dispatch
  request, *args, **kwargs)
File "../django/views/generic/base.py", line 87, in dispatch
  return handler(request, *args, **kwargs)
File "../django/views/generic/edit.py", line 162, in get
  form = self.get_form(form_class)
File "../django/views/generic/edit.py", line 45, in get_form
  return form_class(**self.get_form_kwargs())
File "../django/views/generic/edit.py", line 52, in get_form_kwargs
  'initial': self.get_initial(),
File "../django/utils/decorators.py", line 29, in _wrapper
  return bound_func(*args, **kwargs)
TypeError: _wrapped_view() takes at least 1 argument (0 given)

I am not sure how to resolve this error. Am I applying the decorator on the wrong function? Any leads will be helpful.

like image 219
pxUx Avatar asked Apr 16 '15 18:04

pxUx


People also ask

How is decorator used in class based view?

You need to apply the decorator to the dispatch method of the class based view. This can be done as follows: class ProfileView(View): @youdecorator def dispatch(self,request,*args,**kwargs): return super(ProfileView,self). dispatch(request,*args,**kwargs) //Rest of your code.

How do you use decorators in class based view in Django?

To decorate every instance of a class-based view, you need to decorate the class definition itself. To do this you apply the decorator to the dispatch() method of the class. The decorators will process a request in the order they are passed to the decorator.


1 Answers

Django 1.9 has authentication mixins for class based views. You can use the UserPassesTest mixin as follows.

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

class UserSettingsView(LoginRequiredMixin, UserPassesTestMixin, View):
    def test_func(self):
        return test_settings(self.request.user)

    def get_login_url(self):
        if not self.request.user.is_authenticated():
            return super(UserSettingsView, self).get_login_url()
        else:
            return '/accounts/usertype/'

Note that in this case you have to override get_login_url, because you want to redirect to a different url depending on whether the user is not logged in, or is logged in but fails the test.

For Django 1.8 and earlier, you should decorate the dispatch method, not get_initial.

@method_decorator(user_passes_test(test_settings, login_url='/accounts/usertype/')) 
def dispatch(self, *args, **kwargs):
    return super(UserSettingsView,  self).dispatch(*args, **kwargs)
like image 55
Alasdair Avatar answered Oct 06 '22 22:10

Alasdair