Code

Ticket #4376: django.contrib.auth.decorators.diff

File django.contrib.auth.decorators.diff, 2.7 KB (added by steven.bethard@…, 7 years ago)

rewrite of django.contrib.auth.decorators to handle bound methods properly

Line 
1Index: decorators.py
2===================================================================
3--- decorators.py       (revision 5312)
4+++ decorators.py       (working copy)
5@@ -8,27 +8,16 @@
6     redirecting to the log-in page if necessary. The test should be a callable
7     that takes the user object and returns True if the user passes.
8     """
9-    if not login_url:
10-        from django.conf import settings
11-        login_url = settings.LOGIN_URL
12-    def _dec(view_func):
13-        def _checklogin(request, *args, **kwargs):
14-            if test_func(request.user):
15-                return view_func(request, *args, **kwargs)
16-            return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path())))
17-        _checklogin.__doc__ = view_func.__doc__
18-        _checklogin.__dict__ = view_func.__dict__
19+    def decorate(view_func):
20+        return _CheckLogin(view_func, self.test_func, self.login_url)
21+    return decorate
22 
23-        return _checklogin
24-    return _dec
25-
26-login_required = user_passes_test(lambda u: u.is_authenticated())
27-login_required.__doc__ = (
28+def login_required(view_func):
29     """
30     Decorator for views that checks that the user is logged in, redirecting
31     to the log-in page if necessary.
32     """
33-    )
34+    return _CheckLogin(view_func, lambda u: u.is_authenticated())
35 
36 def permission_required(perm, login_url=None):
37     """
38@@ -37,3 +26,34 @@
39     """
40     return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
41 
42+
43+class _CheckLogin(object):
44+    """
45+    Class that checks that the user passes the given test, redirecting to
46+    the log-in page if necessary. If the test is passed, the view function
47+    is invoked. The test should be a callable that takes the user object
48+    and returns True if the user passes.
49+
50+    We use a class here so that we can define __get__. This way, when a
51+    _CheckLogin object is used as a method decorator, the view function
52+    is properly bound to its instance.
53+    """
54+    def __init__(self, view_func, test_func, login_url=None):
55+        if not login_url:
56+            from django.conf import settings
57+            login_url = settings.LOGIN_URL
58+        self.view_func = view_func
59+        self.test_func = test_func
60+        self.login_url = login_url
61+       
62+    def __get__(self, obj, cls=None):
63+        view_func = self.view_func.__get__(obj, cls)
64+        return _CheckLogin(view_func, self.test_func, self.login_url)
65+   
66+    def __call__(self, request, *args, **kwargs):
67+        if self.test_func(request.user):
68+            return self.view_func(request, *args, **kwargs)
69+        path = quote(request.get_full_path())
70+        tup = self.login_url, REDIRECT_FIELD_NAME, path
71+        return HttpResponseRedirect('%s?%s=%s' % tup)
72+