2012-08-08 32 views
16

Tôi đang sử dụng Django user_passes_test trang trí để kiểm tra quyền người dùng.Làm thế nào để vượt qua đối tượng yêu cầu Django trong user_passes_test decorator chức năng gọi

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

Tôi đang gọi hàm gọi lại has_add_permission nhận hai đối số Người dùng và chuỗi. Tôi muốn vượt qua đối tượng yêu cầu cùng với nó là có thể? Ngoài ra, bất cứ ai có thể xin vui lòng cho tôi biết làm thế nào chúng ta có thể truy cập các đối tượng người dùng bên trong trang trí trực tiếp.

+0

Tôi tò mò, làm thế nào bạn kết thúc việc này? Bạn đã viết trang trí của riêng bạn? – teewuane

+0

Thay vì sử dụng trang trí, tôi đang kiểm tra quyền trong chính mã xem. Nó giúp tôi kiểm soát tốt hơn logic xem. –

+0

Đó cũng là những gì tôi đã làm. Cảm ơn! – teewuane

Trả lời

12

Không, bạn không thể chuyển yêu cầu đến user_passes_test. Để hiểu lý do tại sao và làm thế nào nó hoạt động, chỉ cần đi qua các 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 

Đây là mã đằng sau user_passes_test trang trí. Như bạn có thể thấy, hàm kiểm tra được truyền cho trình trang trí (trong trường hợp của bạn, lambda u: has_add_permission(u, "project")) chỉ được chuyển một đối số, request.user. Bây giờ, tất nhiên là có thể viết trình trang trí của riêng bạn (thậm chí sao chép mã này trực tiếp và chỉ sửa đổi nó) để tự vượt qua request, nhưng bạn không thể làm điều đó với việc thực thi user_passes_test mặc định.

+0

Cảm ơn Chris. Tôi đoán hoặc là tôi phải viết một trang trí mới hoặc làm điều đó bên trong mã xem. –

4

Tôi tìm thấy chỉnh sửa user_passes_test để chức năng trang trí hoạt động trên request thay vì request.user không quá khó khăn. Tôi có một phiên bản ngắn trong this blog post về một trang trí xem trang trí, nhưng đối với hậu thế, đây là mã sửa đầy đủ của tôi:

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 

Khá nhiều điều duy nhất tôi làm là thay đổi if test_func(request.user): để if test_func(request):.

7

Lưu ý rằng Django 1.9 đã giới thiệu UserPassesTestMixin, sử dụng phương thức test_func làm hàm thử nghiệm. Điều này có nghĩa là yêu cầu có sẵn trong self.request. Vì vậy, bạn có thể làm điều gì đó tương tự:

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

Điều này chỉ hoạt động với chế độ xem dựa trên lớp học.

Các vấn đề liên quan