Django:用户登录时发出信号?

ssc*_*ssc 74 python django signals login

在我的Django应用程序中,我需要在用户登录时开始运行一些定期后台作业,并在用户注销时停止运行它们,所以我正在寻找一种优雅的方式

  1. 收到用户登录/注销的通知
  2. 查询用户登录状态

从我的角度来看,理想的解决方案是

  1. 由每个发送的信号django.contrib.auth.views.login... views.logout
  2. 一种方法django.contrib.auth.models.User.is_logged_in(),类似于... User.is_active()... User.is_authenticated()

Django 1.1.1没有那个,我不愿修改源代码并添加它(不知道如何做到这一点,无论如何).

作为临时解决方案,我is_logged_in在UserProfile模型中添加了一个布尔字段,该模型默认情况下已清除,在用户第一次访问登录页面(定义方式LOGIN_REDIRECT_URL = '/')时设置,并在后续请求中查询.我将它添加到UserProfile,因此我不必为此目的派生和定制内置用户模型.

我不喜欢这个解决方案.如果用户明确点击了注销按钮,我可以清除该标志,但大多数时候,用户只需离开页面或关闭浏览器; 在这些情况下清除旗帜对我来说似乎并不直接.此外(尽管数据模型的清晰度很明显),is_logged_in不属于UserProfile,而是属于User模型.

谁能想到替代方法?

Pho*_*beB 142

你可以使用这样的信号(我把它放在models.py中)

from django.contrib.auth.signals import user_logged_in


def do_stuff(sender, user, request, **kwargs):
    whatever...

user_logged_in.connect(do_stuff)
Run Code Online (Sandbox Code Playgroud)

请参阅django docs:https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signals此处http://docs.djangoproject.com/en/dev/专题/信号/

  • 既然Django 1.3提供了这些信号,那么它比将登录/注销呼叫包裹起来要好得多.这也意味着如果您设置新的登录方式 - 例如,Facebook/Twitter/OpenID登录 - 它们仍然可以工作. (8认同)
  • 而不是把它放在`models.py`而不是我建议将代码放在`signals.py`中并在模块的`__init __.py`文件中自动导入它. (8认同)

ShZ*_*ShZ 13

一种选择可能是用自己的方式包装Django的登录/注销视图.例如:

from django.contrib.auth.views import login, logout

def my_login(request, *args, **kwargs):
    response = login(request, *args, **kwargs)
    #fire a signal, or equivalent
    return response

def my_logout(request, *args, **kwargs):
    #fire a signal, or equivalent
    return logout(request, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

然后在代码中使用这些视图而不是Django,并且瞧.

关于查询登录状态,如果您有权访问请求对象,则非常简单; 只需检查请求的用户属性,看看他们是注册用户还是匿名用户,以及宾果游戏.引用Django文档:

if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.
Run Code Online (Sandbox Code Playgroud)

如果您无权访问请求对象,那么确定当前用户是否已登录将很困难.

编辑:

不幸的是,你永远无法获得User.is_logged_in()功能 - 这是HTTP协议的限制.但是,如果你做了一些假设,你可能会接近你想要的.

首先,为什么你不能获得这个功能?好吧,你无法区分关闭浏览器的人或者在获取新浏览器之前在页面上花费一些时间的人之间的区别.当有人实际离开网站或关闭浏览器时,无法通过HTTP告知.

所以你有两个不完美的选择:

  1. 使用Javascript的unload事件来捕获用户离开页面的时间.但是,您必须编写一些谨慎的逻辑,以确保在用户仍在浏览您的网站时不会注销用户.
  2. 每当用户登录时触发注销信号,只是为了确定.还要创建一个经常运行以刷新过期会话的cron作业 - 当删除过期的会话时,检查会话的用户(如果它不是匿名的)没有更多活动会话,在这种情况下,您将触发注销信号.

这些解决方案很混乱,并不理想,但不幸的是,它们是你能做的最好的.


ber*_*ika 9

除了@PhoebeB回答:你也可以使用@receiver像这样的装饰:

from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver

@receiver(user_logged_in)
def post_login(sender, user, request, **kwargs):
    ...do your stuff..`
Run Code Online (Sandbox Code Playgroud)

如果你把它signals.py放在你的app目录中,那么将其添加到app.py:

def ready(self):
    import app_name.signals`
Run Code Online (Sandbox Code Playgroud)