Django:调整@login_required 装饰器
Posted
技术标签:
【中文标题】Django:调整@login_required 装饰器【英文标题】:Django: Tweaking @login_required decorator 【发布时间】:2011-08-06 10:06:31 【问题描述】:我想为我的网站开始一个私人测试版。我有一个启动页面,用户可以在其中输入代码然后访问站点的其余部分。目前,所有其他网站页面(除了启动页面)都包含一系列通过要求用户登录(通过 @login_required 装饰器)设置的重定向。
我希望登录用户和输入 Beta 测试人员代码的用户都能够访问网站的其余部分。这意味着我不能只将装饰器用于我的所有视图。
我应该改变@login_required 装饰器本身吗?我更想做以下事情(如果用户在启动页面上输入正确的代码,我添加了一个会话变量)。
def view_name(request):
user=request.user
if not user.id or not request.session.get('code_success'):
return HttpResponseRedirect('/splash/')
这看起来合理吗?我不想为我的所有观点重复它
布伦丹
【问题讨论】:
【参考方案1】:编写您自己的装饰器 - 相当简单。实际上,如果您查看 login_required
的 Django 源代码,您应该能够为自己的目的摆弄一个副本。
def my_login_required(function):
def wrapper(request, *args, **kw):
user=request.user
if not (user.id and request.session.get('code_success')):
return HttpResponseRedirect('/splash/')
else:
return function(request, *args, **kw)
return wrapper
【讨论】:
嗨史蒂夫,这似乎是一个很好的解决方案。我试了一下。首先,我得到一个回溯,告诉我 renderer() 正在接受一个论点。然后我尝试添加可选的 args/kwargs (renderer(*args, *kwargs)),我得到了一个几乎无法辨认的回溯,声称存在 MiddleWare 错误。然后我从整个函数定义中剥离了 renderer() ,只留下了包装器。这行得通,尽管它无法识别 request.session.get('code_success') 我已经编辑了解决方案(对于看到它的其他人) - 现在看起来正确吗? 是的,现在可以了,史蒂夫。不过,我有一个问题。当我查看其他装饰器时,我经常看到这个 ////return wraps(func)(wrapper)///。看起来 wraps 函数在这里并不相关,但我看过一个类似的教程。那里有什么故事? 我不确定我是否见过这样做的案例 - 你有例子吗? 链接到 Django 源:docs.djangoproject.com/en/dev/_modules/django/contrib/auth/…【参考方案2】:我建议改用中间件。一旦您退出私人测试版,这将使您更容易放弃。在 djangonsippets 上有几个需要登录的中间件示例:
http://djangosnippets.org/snippets/1220/http://djangosnippets.org/snippets/136/
我建议采用其中之一并对其进行调整以包含您的 beta 代码逻辑。
【讨论】:
嗨,马克,这是有道理的。我还没有摆弄使用非标准中间件。 RequireLoginMiddleWare 很酷,肯定会为我节省一些时间。我要试试这两个。谢谢!【参考方案3】:如何重用(调整)内部 Django login_required
例如,您需要只允许通过 login_required 检查并且也是教练的用户访问页面 - 并且(保存)将教练实例传递给您查看进一步处理
装饰器.py
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from profiles.models import CoachProfile
def coach_required(function):
def wrapper(request, *args, **kwargs):
decorated_view_func = login_required(request)
if not decorated_view_func.user.is_authenticated():
return decorated_view_func(request) # return redirect to signin
coach = CoachProfile.get_by_email(request.user.email)
if not coach: # if not coach redirect to home page
return HttpResponseRedirect(reverse('home', args=(), kwargs=))
else:
return function(request, *args, coach=coach, **kwargs)
wrapper.__doc__ = function.__doc__
wrapper.__name__ = function.__name__
return wrapper
views.py
@coach_required
def view_master_schedule(request, coach):
"""coach param is passed from decorator"""
context = 'schedule': coach.schedule()
return render(request, 'template.html', context)
【讨论】:
【参考方案4】:我会创建一个访客帐户,然后将 Beta Tester 代码输入该帐户的用户登录。大致如下:
def beta_code_accepted(request):
guest_user = User.objects.get(username='beta_guest')
login(request, guest_user)
您的测试版完成后,只需禁用启动视图即可。
【讨论】:
对,但我也希望来宾用户能够注册一个完整的帐户。通常,我从登录用户的注册页面重定向。我想我可以允许登录用户注册,这会奏效。我看不出这有什么问题,对吧? 这里的问题是我的应用程序的其他部分有依赖于 user.is_authenticated 上下文变量的逻辑。我不希望测试版的客人能够对某些事情进行烫发。然后,我必须在此方法之上添加一个权限层。 我明白了。也许您可以修改注册页面以检查登录的访客用户。如果您检测到访客帐户,请向他们显示一条消息,建议您注册一个完整帐户或继续以访客身份。以上是关于Django:调整@login_required 装饰器的主要内容,如果未能解决你的问题,请参考以下文章
使用 @login_required 时的 Django 缓存
Django @login_required 删除 https
Django:使用@login_required 在视图上测试失败