The django.contrib.auth.decorators.login_required decorator doesn't work correctly with bound methods. If I have code like:
class ViewManager(object):
@login_required
def get_main_view(self, request):
return HttpResponse('hello')
view_manager = ViewManager()
urlpatterns = patterns('',
(r'^$', view_manager.get_main_view),
)
I'll get an error saying:
AttributeError at /
'ViewManager' object has no attribute 'user'
I believe this is because __get__ is being invoked on the _checklogin function returned by login_required and so the ViewManager? instance is being bound as the request argument of _checklogin instead of being bound as the self argument of get_main_view as it should be. To fix this, I had to replace the _dec function in django.contrib.auth.decorators.user_passes_test like so::
def user_passes_test(test_func, login_url=None):
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
class CheckLogin(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls=None):
return CheckLogin(self.func.__get__(obj, cls))
def __call__(self, request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
return CheckLogin
This simply redirects the __get__ call to the wrapped function, instead of allowing it to be called on the _checklogin function.