2012-08-08 117 views
16

我正在使用Django user_passes_test裝飾器來檢查用戶權限。如何通過user_passes_test中的Django請求對象裝飾器可調用函數

@user_passes_test(lambda u: has_add_permission(u, "project")) 
def create_project(request): 
...... 

我在調用一個回調函數has_add_permission,它有兩個參數User和一個String。我想通過請求對象與它是可能的嗎?另外,任何人都可以告訴我,我們如何能夠直接訪問裝飾器內的用戶對象。

+0

我很好奇,你是怎麼做到的?你有沒有寫自己的裝飾者? – teewuane 2013-12-20 17:00:43

+0

我正在檢查視圖代碼本身內的權限,而不是使用裝飾器。它使我更好地控制視圖邏輯。 – 2013-12-20 18:55:55

+0

這就是我最終做的。謝謝! – teewuane 2013-12-30 20:46:44

回答

12

不,您無法將請求傳遞到user_passes_test。要理解爲什麼和如何工作的,只是頭部到source

def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): 
    """ 
    Decorator for views that checks that the user passes the given test, 
    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. 
    """ 

    def decorator(view_func): 
     @wraps(view_func, assigned=available_attrs(view_func)) 
     def _wrapped_view(request, *args, **kwargs): 
      if test_func(request.user): 
       return view_func(request, *args, **kwargs) 
      path = request.build_absolute_uri() 
      # If the login url is the same scheme and net location then just 
      # use the path as the "next" url. 
      login_scheme, login_netloc = urlparse.urlparse(login_url or 
                 settings.LOGIN_URL)[:2] 
      current_scheme, current_netloc = urlparse.urlparse(path)[:2] 
      if ((not login_scheme or login_scheme == current_scheme) and 
       (not login_netloc or login_netloc == current_netloc)): 
       path = request.get_full_path() 
      from django.contrib.auth.views import redirect_to_login 
      return redirect_to_login(path, login_url, redirect_field_name) 
     return _wrapped_view 
    return decorator 

這是user_passes_test裝飾後面的代碼。正如你所看到的,傳遞給裝飾器的測試函數(在你的情況下,lambda u: has_add_permission(u, "project"))只傳遞一個參數request.user。現在,編寫你自己的裝飾器(甚至直接拷貝這個代碼並修改它)當然也可以通過request本身,但是你不能用默認的user_passes_test實現來完成。

+0

謝謝克里斯。我想我要麼寫一個新的裝飾器,要麼在視圖代碼裏面做。 – 2012-08-08 21:08:37

4

我發現編輯user_passes_test使裝飾功能在request而不是request.user上運行不是太困難。我在this blog post大約視圖修飾裝飾一個短版,但對於後人,這裏是我的全部編輯的代碼:

def request_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): 
    """ 
    Decorator for views that checks that the request passes the given test, 
    redirecting to the log-in page if necessary. The test should be a callable 
    that takes the request object and returns True if the request passes. 
    """ 

    def decorator(view_func): 
     @wraps(view_func, assigned=available_attrs(view_func)) 
     def _wrapped_view(request, *args, **kwargs): 
      if test_func(request): 
       return view_func(request, *args, **kwargs) 
      path = request.build_absolute_uri() 
      # urlparse chokes on lazy objects in Python 3, force to str 
      resolved_login_url = force_str(
       resolve_url(login_url or settings.LOGIN_URL)) 
      # If the login url is the same scheme and net location then just 
      # use the path as the "next" url. 
      login_scheme, login_netloc = urlparse(resolved_login_url)[:2] 
      current_scheme, current_netloc = urlparse(path)[:2] 
      if ((not login_scheme or login_scheme == current_scheme) and 
        (not login_netloc or login_netloc == current_netloc)): 
       path = request.get_full_path() 
      from django.contrib.auth.views import redirect_to_login 
      return redirect_to_login(
       path, resolved_login_url, redirect_field_name) 
     return _wrapped_view 
    return decorator 

差不多我做的唯一的事情就是if test_func(request):變化if test_func(request.user):

7

請注意,Django 1.9引入了UserPassesTestMixin,它使用方法test_func作爲測試函數。這意味着請求可在self.request中獲得。所以你可以這樣做:

class MyView(UserPassesTestMixin, View): 
    def test_func(self): 
     return has_add_permission(self.request.user, self.request) 

但是,這隻適用於基於類的視圖。

相關問題