2008-11-23 28 views
47

我想向我的Django编码网站添加一些Ajax-niceness。Django身份验证和Ajax - 需要登录的URL

在我的Django代码中,我使用django.contrib.auth.decorators@login_required修饰符来标记哪个视图需要身份验证。未经身份验证的用户单击它时的默认行为是将其重定向到登录页面,然后传递目标页面。

我在一些网站上看到的,真的很喜欢的是,当用户点击一个链接导致一个地方被限制为只能记录用户,而不是被重定向到登录页面时,他/她会得到一个弹出窗口(通过JavaScript)要求他/她登录或注册。没有重定向部分,所以如果他/她确定他/她真的不喜欢该网站足以浪费注册时间,则不需要用户使用“后退”键。

所以,问题是:你将如何管理自动将某些链接标记为“受限”的任务,以便JavaScript可以处理它们的onclick事件并显示“请登录”弹出窗口?

回答

53

I我面临着同样的问题,并且像你一样,我想要一个简单的装饰器来包装Django ajax视图,以便像处理其他视图一样处理身份验证。对我来说,看起来很有前途的一种方法是将这样的装饰器与JavaScript结合使用,在响应中寻找特定的值。

这里是第一修订装饰的草案:

from functools import wraps 

def ajax_login_required(view_func): 
    @wraps(view_func) 
    def wrapper(request, *args, **kwargs): 
     if request.user.is_authenticated(): 
      return view_func(request, *args, **kwargs) 
     json = simplejson.dumps({ 'not_authenticated': True }) 
     return HttpResponse(json, mimetype='application/json') 
    return wrapper 

这里是视图:

@ajax_login_required 
def ajax_update_module(request, module_slug, action): 
    # Etc ... 
    return HttpResponse(json, mimetype='application/json') 

这里是JavaScript(jQuery的):

$.post('/restricted-url/', data, function(json) { 
    if (json.not_authenticated) { 
     alert('Not authorized.'); // Or something in a message DIV 
     return; 
    } 
    // Etc ... 
}); 

编辑:我试图按照建议使用functools.wraps。我实际上并没有在工作代码中使用这个装饰器,所以要小心可能的错误。

5

听起来像一个页面模板可能性。

  1. 你可以通过一个LINK_VIA(或某事),你提供尽可能onClick="return popup(this, 'arg')"None。每个链接将是<A HREF="link" {{LINK_VIA}}>some text</a>

    • 对于匿名会话,LINK_VIA有一个值。
    • 对于会议记录,LINK_VIA是无
  2. 你可以使用一个{% if %}声明在你的<A HREF=...>标签。这似乎罗嗦。

  3. 您可以编写自己的自定义标签为{% link_via %}。我对此不够熟悉,但是您可以将链接和文本作为字符串提供,并且您的代码可以生成两种链接中的一种。

+0

什么我不知道是怎么从模板的角度确定链接导致的视图是否用@login_required装饰或不... – kender 2008-11-23 22:07:05

+0

该模板没有随机链接。它具有您在模板中专门设计和编码的特定链接。我建议你改变你在模板中专门放置的每个链接。 – 2008-11-23 22:27:21

5

我会同意S.Lott

使模板检查,如果用户登录,只是把链接像往常一样,如果没有,把像

<a href="{{link}}" onclick="return login_popup()"> 

如果用户说取消,login_popup将返回false。

Jinja2macros之间,这可能会更容易完成。

如果模板不知道哪些URL需要用户登录,那么您可能需要重新考虑您的设计。

如果你肯定,我想你可以做同样的事情,django网址调度程序发现视图函数。
请参阅:django.core.urlresolvers

一旦您已经抓住视图函数,您可以检查它是否用@login_required装饰。

这可能会在自定义标记中完成。
如果你使用Jinja2,你不需要标签,只需实现该功能并将其暴露给环境,这很简单,但你必须做一些阅读Jinja2的API)

+0

我对这个派对狂热地迟到了,但是无论如何:这只是因为用户可以直接链接到所讨论的页面,这种情况下,需要登录所需的弹出方法将会中断。 – 2013-01-31 19:23:53

1

这里建议用保鲜.__ doc__会给出装饰的版本,包装.__ name__

from functools import wraps 

def ajax_login_required(function): 
    def wrap(request, *args, **kwargs): 
     if request.user.is_authenticated(): 
      return function(request, *args, **kwargs) 
     json = simplejson.dumps({ 'not_authenticated': True }) 
     return HttpResponse(json, mimetype='application/json') 
    wrap.__doc__ = function.__doc__ 
    wrap.__name__ = function.__name__ 
    return wrap 
0

内置断Eric Walker's解决方案,但Django的2.0

# Standard Imports 
import functools 
import django.http 

def ajax_login_required(view_func): 
    @functools.wraps(view_func) 
    def wrapper(request, *args, **kwargs): 
     if request.user.is_authenticated: 
      return view_func(request, *args, **kwargs) 

     return django.http.JsonResponse('Unauthorized', status=401, safe=False) 

    return wrapper