Django:用户login时发出信号?
在我的Django应用程序中,我需要在用户login时开始运行一些周期性的后台作业,并在用户注销时停止运行它们,所以我正在寻找一种优雅的方式
- 得到用户login/注销的通知
- 查询用户login状态
从我的angular度来看,理想的解决scheme是
- 由每个
django.contrib.auth.views.login
和... views.logout
发送的信号 - 一个方法
django.contrib.auth.models.User.is_logged_in()
,类似于... User.is_active()
或... User.is_authenticated()
Django 1.1.1没有这个,我不愿意补丁的源代码并添加它(不知道如何做到这一点,无论如何)。
作为一个临时的解决scheme,我在UserProfile模型中添加了一个is_logged_in
boolean字段,默认情况下这个字段被清除,用户首次访问登陆页面(由LOGIN_REDIRECT_URL = '/'
定义),并在随后的请求中被查询。 我将它添加到UserProfile中,所以我不必从这个目的派生和定制内build的用户模型。
我不喜欢这个解决scheme。 如果用户明确地点击注销button,我可以清除标志,但大多数时候,用户只是离开页面或closures浏览器; 在这些情况下清除国旗似乎并不是直截了当的。 除此之外(虽然这是数据模型的清晰度),但is_logged_in
不属于UserProfile,而是属于User模型。
任何人都可以想到替代方法?
你可以使用这样的信号(我把它放在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)
请参阅django文档: https : //docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signals and here http://docs.djangoproject.com/en/dev/专题/信号/
一个选项可能是用你自己的方式来包装Django的login/注销视图。 例如:
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)
然后你在代码中使用这些视图而不是Django的视图,瞧。
关于查询login状态,如果你有权访问请求对象,这很简单; 只要检查请求的用户属性,看看他们是一个注册用户或匿名用户,宾果。 引用Django文档 :
if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users.
如果您无法访问请求对象,那么确定当前用户是否login将很困难。
编辑:
不幸的是,你将永远无法获得User.is_logged_in()
function – 这是HTTP协议的限制。 但是,如果你做了一些假设,你可能会接近你想要的。
首先,为什么你不能得到这个function? 那么,你不能分辨出closures浏览器的某个人或者在页面上花费一些时间的人在获取一个新页面之前的区别。 当有人真正离开网站或closures浏览器时,无法通过HTTP进行分析。
所以你在这里有两个select是不完美的:
- 当用户离开页面时,使用Javascript的
unload
事件。 但是,您必须编写一些谨慎的逻辑,以确保在用户仍然在浏览您的网站时不会注销用户。 - 只要用户login,就可以触发注销信号。 还要创build一个经常运行的cron作业来清除过期的会话 – 当过期的会话被删除时,检查会话的用户(如果不是匿名的)没有更多的活动会话,在这种情况下,您将触发注销信号。
这些解决scheme是混乱和不理想的,但不幸的是,他们是最好的。
唯一可靠的方法(也检测用户何时closures浏览器)是每次用户加载页面时更新一些last_request
字段。
如果用户打开一个页面,您也可以定期发送AJAX请求,每隔x分钟对服务器进行一次ping命令。
然后让一个后台作业获取最近的用户列表,为他们创build作业,并清除不在该列表中的用户的作业。
推断注销,而不是让他们明确地点击一个button(没有人做),意味着select相当于“注销”的空闲时间。 phpMyAdmin使用默认的15分钟,一些银行网站使用只有5分钟。
实现这个最简单的方法是改变cookie的生命周期。 您可以通过指定settings.SESSION_COOKIE_AGE
为您的整个网站做到这一点。 或者,您可以通过使用HttpResponse.setcookie()
以每个用户为基础(基于一些任意的标准)对其进行更改。 您可以通过创build自己的render_to_response()
版本来集中这些代码,并在每个响应中设置生命周期。
粗糙的想法 – 你可以使用这个中间件。 当请求相关的URL时,这个中间件可以处理请求和触发信号。 当行动实际上成功时,它也可以处理响应和火警信号。
你可以这样使用:
from django.contrib.auth.signals import user_logged_out, user_logged_in @login_required def user_logout(request): logout(request) user_logged_out() return redirect('post_list')
除了@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..`
如果你把它放在你的应用程序目录中的app.py
,那么把它添加到app.py
:
def ready(self): import app_name.signals`