Index: decorators.py
===================================================================
--- decorators.py	(revision 5312)
+++ decorators.py	(working copy)
@@ -8,27 +8,16 @@
     redirecting to the log-in page if necessary. The test should be a callable
     that takes the user object and returns True if the user passes.
     """
-    if not login_url:
-        from django.conf import settings
-        login_url = settings.LOGIN_URL
-    def _dec(view_func):
-        def _checklogin(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())))
-        _checklogin.__doc__ = view_func.__doc__
-        _checklogin.__dict__ = view_func.__dict__
+    def decorate(view_func):
+        return _CheckLogin(view_func, self.test_func, self.login_url)
+    return decorate
 
-        return _checklogin
-    return _dec
-
-login_required = user_passes_test(lambda u: u.is_authenticated())
-login_required.__doc__ = (
+def login_required(view_func):
     """
     Decorator for views that checks that the user is logged in, redirecting
     to the log-in page if necessary.
     """
-    )
+    return _CheckLogin(view_func, lambda u: u.is_authenticated())
 
 def permission_required(perm, login_url=None):
     """
@@ -37,3 +26,34 @@
     """
     return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
 
+
+class _CheckLogin(object):
+    """
+    Class that checks that the user passes the given test, redirecting to
+    the log-in page if necessary. If the test is passed, the view function
+    is invoked. The test should be a callable that takes the user object
+    and returns True if the user passes.
+
+    We use a class here so that we can define __get__. This way, when a
+    _CheckLogin object is used as a method decorator, the view function
+    is properly bound to its instance.
+    """
+    def __init__(self, view_func, test_func, login_url=None):
+        if not login_url:
+            from django.conf import settings
+            login_url = settings.LOGIN_URL
+        self.view_func = view_func
+        self.test_func = test_func
+        self.login_url = login_url
+        
+    def __get__(self, obj, cls=None):
+        view_func = self.view_func.__get__(obj, cls)
+        return _CheckLogin(view_func, self.test_func, self.login_url)
+    
+    def __call__(self, request, *args, **kwargs):
+        if self.test_func(request.user):
+            return self.view_func(request, *args, **kwargs)
+        path = quote(request.get_full_path())
+        tup = self.login_url, REDIRECT_FIELD_NAME, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)
+
