如何在自定义Django装饰器内调用login_required,无需使用两个独立装饰器?
当然可以!其实在自定义装饰器里复用Django原生的login_required逻辑有几种优雅的方式,完全不用叠加两个独立装饰器或者重复造轮子。下面给你分享几种实用的实现思路:
方法一:在自定义装饰器内部调用login_required包装后的视图
这种方式最直接,先让login_required完成认证校验,再执行你的自定义权限检查,完全复用原生逻辑:
from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from functools import wraps def my_custom_decorator(view_func): # 先用login_required包装原视图,复用它的认证逻辑 login_protected_view = login_required(view_func) @wraps(view_func) def wrapper(request, *args, **kwargs): # 先执行login_required的逻辑:未认证会直接跳转到登录页 response = login_protected_view(request, *args, **kwargs) # 能走到这一步,说明用户已经通过认证,开始自定义权限校验 if not has_page_access(request.user): # 替换成你的权限判断函数 return HttpResponseForbidden("你没有访问该页面的权限") # 权限校验通过,返回原视图的响应 return response return wrapper
这样做的好处是:不用关心login_required内部的细节(比如next参数处理、登录页跳转逻辑),所有原生认证逻辑都直接复用,你只需要专注于自己的权限规则。
方法二:合并两个装饰器为一个新装饰器
如果希望视图代码更简洁,你可以把login_required和自定义权限逻辑嵌套成一个装饰器,对外只暴露一个接口:
from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from functools import wraps def login_and_permission_required(view_func): # 先应用login_required,再叠加自定义权限检查 @login_required @wraps(view_func) def wrapper(request, *args, **kwargs): # 自定义权限校验逻辑 if not has_page_access(request.user): return HttpResponseForbidden("权限不足,无法访问") return view_func(request, *args, **kwargs) return wrapper
使用的时候直接在视图上用@login_and_permission_required就可以,相当于把两个装饰器的逻辑合并成了一个,既简洁又保证了认证在前、权限检查在后的顺序。
方法三:支持参数的自定义装饰器
如果需要给login_required传递自定义参数(比如指定login_url),可以让你的装饰器支持参数传递,内部动态调用带参数的login_required:
from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from functools import wraps def my_custom_decorator(login_url=None): def decorator(view_func): # 根据传入的参数配置login_required login_protected = login_required(login_url=login_url)(view_func) @wraps(view_func) def wrapper(request, *args, **kwargs): response = login_protected(request, *args, **kwargs) # 自定义权限检查 if not has_page_access(request.user): return HttpResponseForbidden("无访问权限") return response return wrapper return decorator
使用时可以像这样传参:
@my_custom_decorator(login_url='/custom-login-page/') def my_view(request): # 视图逻辑 pass
为什么推荐复用login_required而不是自己写认证判断?
自己写if not request.user.is_authenticated:虽然简单,但login_required做的远不止这一个判断:它会自动处理匿名用户的跳转,把当前页面URL作为next参数传递给登录页,登录成功后还会自动跳回原页面——这些细节如果自己实现很容易遗漏,复用原生装饰器能避免这些坑,还能保持代码和Django的原生逻辑一致。
内容的提问来源于stack exchange,提问作者Eduard Luca
相关产品推荐
相关产品推荐

