Django注销不起作用
Posted
技术标签:
【中文标题】Django注销不起作用【英文标题】:Django logout not working 【发布时间】:2012-12-10 21:49:24 【问题描述】:我似乎遇到了和这个问题一样的问题:Django logout problem
我的有点奇怪,它可以在 google chrome 中运行……但在 Firefox 中不行……
这是我的注销功能:(在views.py中)
def my_logout(request):
logger.debug("Logout called by user")
try:
# Here I do some custom stuff, like logging this action in a database and so on
# For this question it shouldn't matter... because in a try catch
# so whatever goes wrong here, logging out should work anyway
except Exception, e:
logger.info("Logging logout action error: %s" % e)
logout(request)
return HttpResponseRedirect("/")
在 settings.py 我有:
LOGIN_URL = '/desktop/login/'
LOGOUT_URL = '/desktop/logout/'
LOGIN_REDIRECT_URL = '/'
在应用程序iamapps 的urls.py 中(包括在项目url 中为/desktop/):
url(r'^login/$', 'iamapps.views.my_login', name='iamapps.login'),
url(r'^logout/$', 'iamapps.views.my_logout', name='iamapps.logout'),
更多信息:
django 1.4.3(刚刚从 1.3 更新到 1.4 ....) python 2.7 适用于 Chrome,但不适用于 Firefox 17.0.1、Linux它可以在 google chrome 中运行但在 Firefox 中不起作用的事实最让我困惑。似乎它与firefox不断记住用户正在登录有关......
编辑: 我的管道坏了......但我似乎不是在注销时得到它......而是在注销后进入主视图......
Traceback (most recent call last):
File "/usr/lib/python2.7/wsgiref/handlers.py", line 86, in run
self.finish_response()
File "/usr/lib/python2.7/wsgiref/handlers.py", line 127, in finish_response
self.write(data)
File "/usr/lib/python2.7/wsgiref/handlers.py", line 210, in write
self.send_headers()
File "/usr/lib/python2.7/wsgiref/handlers.py", line 268, in send_headers
self.send_preamble()
File "/usr/lib/python2.7/wsgiref/handlers.py", line 192, in send_preamble
'Date: %s\r\n' % format_date_time(time.time())
File "/usr/lib/python2.7/socket.py", line 324, in write
self.flush()
File "/usr/lib/python2.7/socket.py", line 303, in flush
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 58684)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 582, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 323, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/media/storage/django/sites/iamfloraservice/parts/django/django/core/servers/basehttp.py", line 139, in __init__
super(WSGIRequestHandler, self).__init__(*args, **kwargs)
File "/usr/lib/python2.7/SocketServer.py", line 641, in __init__
self.finish()
File "/usr/lib/python2.7/SocketServer.py", line 694, in finish
self.wfile.flush()
File "/usr/lib/python2.7/socket.py", line 303, in flush
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
[24/Dec/2012 14:33:25] "GET / HTTP/1.1" 200 48247
编辑 2 登出并被重定向后进入此视图:
def home(request, template='iamfloraservice/home.html'):
logger.debug("Home view called by user %s" % request.user)
return render_to_response(template,,context_instance=RequestContext(request))
我认为将请求重定向到此视图会导致问题.... 在日志中它仍然是用户'michel'(因为视图使用来自重定向的请求,并且有用户michel)......但是......同时用户michel正在被注销......
编辑 3
因为建议是由于记录器。 取消记录日志没有帮助 它是默认记录器:
import logging
logger = logging.getLogger(__name__)
编辑 4 (30-12-2012)
我的注销来自一个主窗口,当用户登录时我会显示一个注销链接,如果用户注销,我会显示一个登录链接。它还包含一个工具栏,根据用户及其组成员身份填充哪些工具。
我认为问题在于,它正在重新加载此主窗口,而缓存和它的请求中的用户尚未清除。不知何故,Chrome 知道如何处理这个问题,而 Firefox 会导致管道损坏错误。在浏览器中手动清除缓存会在重新加载后显示正确的视图....
一个解决方案可能是重定向到一个没有任何包含用户的页面...... 或者自己找出在正确的时刻清除缓存....
这个问题描述的可能相同......但我不能指望用户在浏览器中做任何事情只是为了注销?见django 1.4 caching GET to /login/
编辑 5 (31-12-2012)
这似乎是一个缓存问题....但不知道如何解决这个问题。
这些是我的缓存设置:
if not DEBUG:
CACHES =
'default':
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
else:
CACHES =
'default':
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
但我也尝试不使用 dummycache
编辑 6(2013 年 1 月 4 日) 仍然没有解决方案....我将注销方式更改为django方式,现在我正在使用信号...请参阅下面的我自己的答案。
但它仍然给出了损坏的管道错误,导致 firefox 停止注销。这不是缓存问题。如果我转到另一个页面,或者更糟糕的是......管理页面。我仍然登录。注销的唯一方法是通过管理页面上的注销....如果它不是管理员用户...没有办法让我在 firefox 浏览器上注销。
使用管理界面注销时,信号正常...
我通过关闭信号进行了检查......仍然无法在Firefox中注销。
结论:回到主页面()导致问题。
编辑 7(2013 年 1 月 4 日) 我做了一个简单的注销视图进行测试, 这个模板:
<html>
<head>
<title>
Logged out
</title>
</head>
<body>
You are succesfully logged out.<br>
<br>
<a href="/">Go back to the main page</a>
or<br>
<a href="/desktop/login/?next=/">log in again</a>
</body>
</html>
和注销的视图:
class LoggedOutView(TemplateView):
template_name = "iamapps/logged_out.html"
并将网址更改为:
url(r'^logout/$', 'django.contrib.auth.views.logout', 'next_page': '/desktop/loggedout/', name='iamapps.logout'),
#url(r'^logout/$', 'django.contrib.auth.views.logout_then_login', name='iamapps.logout'),
url(r'^loggedout/$', LoggedOutView.as_view(),name='iamapps.loggedout'),
不过,为了简单起见...我已经关闭了信号。
它仍然无法在 firefox 中运行......但它可以在 chrome 中运行
在 Firefox 中它不会转到已注销的页面
【问题讨论】:
您在调用注销时是否收到任何错误消息? @AamirAdnan:谢谢,我忘了提那个... 我认为问题出在您的记录器上。您能否在不记录任何信息的情况下测试my_logout
视图,而不是使用print
语句。
感谢您的宝贵时间,但这是默认的 django 记录器。我在它前面放了一个备注标志,没有帮助。
浏览器会发生什么?您是否被重定向到/
但仍保持登录状态?这种情况下首页可以缓存吗?
【参考方案1】:
我通常只使用贡献视图来注销用户。只需将其添加到您的根 urls.py
文件中:
# Would be nice to use settings.LOGIN_URL for `next_page` here, too
url(r'^logout/$', 'django.contrib.auth.views.logout', 'next_page': '/login'),
你会很高兴的。
快乐的 Djangoing。
【讨论】:
首先感谢您在圣诞节期间的宝贵时间! (祝大家圣诞快乐)。看到我不是唯一一个有这个问题的人,这极大地支持了我。但是,根据你的建议,我不能再做我的自定义东西了......那将是放弃......这对我来说并不高兴 :) 我会给你一些分数...看我的回答...你的回答是解决方案的一部分....剩下的就是添加信号。 对了,为什么不用logout_than_login ...见docs.djangoproject.com/en/dev/topics/auth/default/… 为使用 url(r'^logout', views.logout, name='logout') 调用注销(请求)而苦苦挣扎了一段时间,但我失败了。非常感谢这个干净的解决方案【参考方案2】:最后我完全切换到几乎回到 django 默认值... 使用:
在views.py中:
from django.contrib.auth.forms import AuthenticationForm
from django.views.generic.edit import FormView
class LoginView(FormView):
"""
This is a class based version of django.contrib.auth.views.login.
"""
form_class = AuthenticationForm
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'iamapps/login.html'
@method_decorator(csrf_protect)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(LoginView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
"""
The user has provided valid credentials (this was checked in AuthenticationForm.is_valid()). So now we
can check the test cookie stuff and log him in.
"""
self.check_and_delete_test_cookie()
login(self.request, form.get_user())
return super(LoginView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(LoginView, self).get_context_data(**kwargs)
apps_settings=iamapps_settings()
if apps_settings[LOGON_BASE_APP_NAME]:
self.extend_template="%s/base.html" % apps_settings[LOGON_BASE_APP_NAME]
else:
self.extend_template="iamapps/base.html"
context['extend_template']=self.extend_template
return context
def form_invalid(self, form):
"""
The user has provided invalid credentials (this was checked in AuthenticationForm.is_valid()). So now we
set the test cookie again and re-render the form with errors.
"""
self.set_test_cookie()
return super(LoginView, self).form_invalid(form)
def get_success_url(self):
if self.success_url:
redirect_to = self.success_url
else:
redirect_to = self.request.REQUEST.get(self.redirect_field_name, '')
netloc = urlparse.urlparse(redirect_to)[1]
if not redirect_to:
redirect_to = settings.LOGIN_REDIRECT_URL
# Security check -- don't allow redirection to a different host.
elif netloc and netloc != self.request.get_host():
redirect_to = settings.LOGIN_REDIRECT_URL
return redirect_to
def set_test_cookie(self):
self.request.session.set_test_cookie()
def check_and_delete_test_cookie(self):
if self.request.session.test_cookie_worked():
self.request.session.delete_test_cookie()
return True
return False
def get(self, request, *args, **kwargs):
"""
Same as django.views.generic.edit.ProcessFormView.get(), but adds test cookie stuff
"""
self.set_test_cookie()
return super(LoginView, self).get(request, *args, **kwargs)
和网址:
url(r'^login/$', LoginView.as_view(), name='login'),
这解决了我所有的麻烦...关于登录和注销...
登录和注销信号正常工作:
from django.contrib.auth.signals import user_logged_out, user_logged_in
# Note, these login and logout signals are registered in imamstats views
def iam_logged_out_actions(sender, user, request, **kwargs):
try:
# ... do my logging out actiosn (stats etc.)
except Exception, e:
logger.error("Logging logout action error: %s" % e)
# Note, these login and logout signals are registered in imamstats views
def iam_logged_in_actions(sender, user, request, **kwargs):
try:
# ... do my log in stats etc. things
except Exception, e:
logger.error("Logging login action error: %s" % e)
【讨论】:
【参考方案3】:浏览到 ***...(进行了另一次搜索)
我找到了这个:.. 见 django.contrib.auth.logout in Django ..
但更糟糕的是......我发现这......很惊讶......但解释了这一切: Django, Logout_URL doesn't redirect well
我发现这是一个无法修复的错误 (@##$%%) 不允许在平安夜诅咒....
因此,做我的自定义工作的解决方案是在信号中,而不是使用我自己的视图。 执行默认视图并重定向... 并使用此文档创建信号.. https://docs.djangoproject.com/en/dev/topics/auth/#login-and-logout-signals
添加信号非常简单,我将它放在我的主应用程序 (iamapps) 的 models.py 中:
import logging
from django.contrib.auth.signals import user_logged_out
from django.contrib.auth.signals import user_logged_in
logger = logging.getLogger(__name__)
def iam_logged_out_actions(sender, user, request, **kwargs):
#whatever...
logger.debug("Logging out: user = %s" % user)
user_logged_out.connect(iam_logged_out_actions)
def iam_logged_in_actions(sender, user, request, **kwargs):
#whatever...
logger.debug("Logging in: user = %s" % user)
user_logged_in.connect(iam_logged_in_actions)
这有效....但是它不能解决我认为可能导致注销失败的损坏管道...所以在 Firefox 中注销仍然失败...在 chrome 中它可以工作... 从 django 管理页面注销可以在 firefox 中使用。而且该信号还有另一个优点:也是从管理界面中注销,正在调用该信号...
为了注销我现在使用这个 urls.py:
url(r'^logout/$', 'django.contrib.auth.views.logout', 'next_page': '/', name='iamapps.logout'),
【讨论】:
【参考方案4】:我的怀疑是原始注销视图返回一个清除 cookie 或类似内容的响应,而您正在丢弃该响应。您可以尝试像这样简单地将其响应返回给用户吗?
def my_logout(request):
# something...
return logout(request)
【讨论】:
这无济于事。它给出了一个错误“视图iamapps.views.iam_logout 没有返回一个HttpResponse 对象。”但它让我学到了一些新东西。 Firefox 甚至不会到达那里......只有 chrome 给出了这个错误...... @michel.iamit:其他想法:1)你的“某事”可能会在return
上做一些奇怪的事情; 2)您没有导入/使用正确的通用注销视图; 3)通用注销视图以某种方式被阻止或丢弃
我改变了我完全注销的方式,并使用通用注销,请参阅上面的答案。我现在正在使用这些信号。在信号中,我将某些内容保存到数据库中,在该数据库中我使用了请求中的用户....但它仍然不起作用....似乎注销过程不等待信号被处理... 【参考方案5】:
经过验证的答案适用于上述版本,但它不再适用于 django 2.2 版本。因此,为了在注销后成功重定向,您必须定义属性。
from django.contrib import admin
from django.urls import path, include
from dark_bot import views
from django.contrib.auth import views as v
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index, name="index"),
path('contact/', views.contact, name="contact"),
path('search/', include('search.urls')),
path('user/', include('accounts.urls')),
path('dashboard/', include('dashboard.urls')),
path('accounts/login/', v.LoginView.as_view(), name="login"),
path('accounts/logout/',v.LogoutView.as_view(next_page='/'),name="logout")
# path('dashboard/', include('dashboard.urls')),
]
这就是你可以看到我将 next_page 属性传递给类 LogoutView 的方式,它将告诉在成功注销后重定向或去哪里。 希望这可以帮助某人。 快乐编码!
【讨论】:
以上是关于Django注销不起作用的主要内容,如果未能解决你的问题,请参考以下文章