Monkey patched django auth's login, now its tests fail - django

My app seeks to wrap the django.contrib.auth.views login and logout views with some basic auditing/logging capabilities. I'm following the prescription as described in the django-axes project, and in running on a server and some other tests, it works as expected, transparently without issue.
The code goes like this:
from django.contrib.auth import views as auth_views
from myapp.watchers import watch_login
class WatcherMiddleware(object):
def __init__(self):
auth_views.login = watch_login(auth_views.login)
And
def watch_login(func):
def decorated_login(request, *args, **kwargs):
#do some stuff
response = func(request, *args, **kwargs)
#more stuff
return response
return decorated_login
Urls:
#Edit: Added project's urls - just using vanilla django's auth login
(r'^accounts/login/$', 'django.contrib.auth.views.login',{"template_name":settings.LOGIN_TEMPLATE }),
However, in our build workflow, we run into some issues in the django.contrib.auth.tests.views.
Specifically, these are the tests that fail in django.contrib.auth:
ERROR: test_current_site_in_context_after_login (django.contrib.auth.tests.views.LoginTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python26\lib\site-packages\django\contrib\auth\tests\views.py", line 192, in test_current_site_in_context_after_login
response = self.client.get(reverse('django.contrib.auth.views.login'))
File "C:\Python26\lib\site-packages\django\core\urlresolvers.py", line 351, in reverse
*args, **kwargs)))
File "C:\Python26\lib\site-packages\django\core\urlresolvers.py", line 297, in reverse
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
NoReverseMatch: Reverse for 'myapp.watchers.decorated_login' with arguments '()' and keyword arguments '{}' not found.
======================================================================
ERROR: test_security_check (django.contrib.auth.tests.views.LoginTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python26\lib\site-packages\django\contrib\auth\tests\views.py", line 204, in test_security_check
login_url = reverse('django.contrib.auth.views.login')
File "C:\Python26\lib\site-packages\django\core\urlresolvers.py", line 351, in reverse
*args, **kwargs)))
File "C:\Python26\lib\site-packages\django\core\urlresolvers.py", line 297, in reverse
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
NoReverseMatch: Reverse for 'myapp.watchers.decorated_login' with arguments '()' and keyword arguments '{}' not found.
Only these two tests fail with the inclusion of the wrapped login monkey patch.
It seems like the reverse() call in the django auth test behaves differently than how an unpatched function does its thing.
The reason why we're going this route for wrapping logging vs. using django 1.3's new authentication signals is because the logging method provided there only tells you if a wrong attempts happens - it doesn't give you access to the request object to log additional information around that improper request. Patching the authentication form in that case would not have been helpful, hence our need to wrap the login function.
Am I doing something wrong with my wrap of the login function? Or is this as to be expected with tests failing due to other side effects, despite no change in overall functionality?
edit: I'm running python 2.6.4, django 1.2.5

Couldn't you simply wrap it in another view?
urls:
url(
r'^accounts/login/$',
'accounts.views.login',
{"template_name":settings.LOGIN_TEMPLATE }
),
accounts.views:
from django.contrib.auth import views as auth_views
def login(request, *args, **kwars):
# do some stuff
response = auth_views.login(request, *args, **kwars)
# more stuff
return response
Like this, django.contrib.auth.tests will be testing the view which they were written for and you can write your own tests for the "more stuff" you need.

I suspect this is the same underlying issue that affects django-registration in that the test runner only imports the URLs of the app being tested at the time -- ie, contrib.auth and not myapp There are various tickets about things similar to this issue but a quick scan of them implies the solution is to decouple things, which isn't going to be viable for your solution I'm guessing.
Another way around it would be to use Fabric file or Makefile to trigger a subset of tests, avoiding the two that fail because of your monkeypatch, and then add two alternate ape-friendly tests to replace them.

Related

Django Rest Framework URL for custom action not working

I've got the following custom action in my view:
class OrderAPIViewSet(viewsets.ViewSet):
def create(self, request):
print("Here: working")
#action(detail=True, methods=['post'])
def add(self, request, *arg, **kwargs):
print("HERE in custom action")
order = self.get_object()
print(order)
my app's urls.py is:
from rest_framework import routers
from .views import OrderAPIViewSet
router = routers.DefaultRouter()
router.register(r'orders', OrderAPIViewSet, basename='order')
urlpatterns = router.urls
So in my test when I try to access orders/post it works, but when I try to access orders/{pk}/add it fails. I mean, the reverse itself is failing:
ORDERS_LIST_URL = reverse('order-list')
ORDERS_ADD_URL = reverse('order-add')
class PublicOrderApiTests(TestCase):
def test_sample_test(self):
data = {}
res = self.client.post(ORDERS_ADD_URL, data, format='json')
as I said before, I've got a separate test where I use ORDERS_LIST_URL like this:
res = self.client.post(ORDERS_LIST_URL, data, format='json')
but when running the test I'm getting the following error:
ImportError: Failed to import test module: orders.tests Traceback
(most recent call last): File
"/usr/local/lib/python3.7/unittest/loader.py", line 436, in
_find_test_path
module = self._get_module_from_name(name) File "/usr/local/lib/python3.7/unittest/loader.py", line 377, in
_get_module_from_name
import(name) File "/app/orders/tests.py", line 22, in
ORDERS_ADD_URL = reverse('order-add') File "/usr/local/lib/python3.7/site-packages/django/urls/base.py", line 87,
in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)) File "/usr/local/lib/python3.7/site-packages/django/urls/resolvers.py",
line 685, in _reverse_with_prefix
raise NoReverseMatch(msg) django.urls.exceptions.NoReverseMatch: Reverse for 'order-add' with no arguments not found. 2 pattern(s)
tried: ['orders/(?P[^/.]+)/add\.(?P[a-z0-9]+)/?$',
'orders/(?P[^/.]+)/add/$']
---------------------------------------------------------------------- Ran 1 test in 0.000s
FAILED (errors=1)
according to the documentation I shouldn't need to register this endpoint, the router is supposed to do it by itself. What am I missing?
The first thing that you've missed is pk in your reverse. Since the add API needs a pk of your Order object, you need to pass it to reverse function. For example:
order_add_url = reverse('order-add', kwargs={'pk': 1})
print(order_add_url) # which will print '/orders/1/add/'
So I think you should move this part to the body of PublicOrderApiTests's methods since you need a dynamic url per test object.
Another problem is that the ViewSet class does not support self.get_object() and if you want to use this method you should either have your own method or use rest framework GenericViewSet (i.e. from rest_framework.viewsets import GenericViewSet and inherit from this class instead of ViewSet) then you can access the get_object() method. You can also read more about generic views in rest framework docs.

URL resolution issues in Django Tests

I've written a django model that has a get_absolute_url method, with unit tests to make sure everything is kosher. The get_absolute_url tests pass no problem. The get_absolute_url method is written as so
def get_absolute_url(self):
return reverse("scheduling:klass", args=[self.pk])
This is the url routing to give context about how the urls flow.
#main.urls
urlpatterns = [
url(r'^$', homepage, name="home"),
url(r'^scheduling/', include('scheduling.urls', namespace="scheduling")),
url(r'^profile/', include('user_profile.urls', namespace="profile")),
url(r'^accounts/', include('allauth.urls')),
url(r'^admin/', admin.site.urls),
]
#scheduling.urls
urlpatterns = [
url(r'add-class/$', views.add_klass, name="add_klass"),
url(r'class/(?P<pk>\d+)/$', views.klass, name="klass"),
]
I'm testing the klass view (it's basically just a klass detail view) as follows
def test_klass_detail_template_renders(self):
print(self.klass.pk)
response = self.client.get(self.klass.get_absolute_url())
self.assertTemplateUsed(response, "scheduling/klass.html")
The test fails with the following stacktrace.
======================================================================
ERROR: test_klass_detail_template_renders (scheduling.tests.test_views.KlassViewTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/core/urlresolvers.py", line 586, in reverse
extra, resolver = resolver.namespace_dict[ns]
KeyError: 'myproject.profile'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/template/defaulttags.py", line 507, in render
current_app=current_app)
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/core/urlresolvers.py", line 596, in reverse
key)
django.core.urlresolvers.NoReverseMatch: 'myproject.profile' is not a registered namespace
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/me/Documents/Development/myproject/src/scheduling/tests/test_views.py", line 60, in test_klass_detail_template_renders
response = self.client.get(self.klass.get_absolute_url())
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/test/client.py", line 503, in get
**extra)
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/test/client.py", line 304, in get
return self.generic('GET', path, secure=secure, **r)
...
File "/Users/me/.virtualenvs/myproject/lib/python3.5/site-packages/django/core/urlresolvers.py", line 508, in _reverse_with_prefix
(lookup_view_s, args, kwargs, len(patterns), patterns))
django.core.urlresolvers.NoReverseMatch: Reverse for 'profile' with arguments '('',)' and keyword arguments '{}' not found. 2 pattern(s) tried: ['profile/$', 'profile/(?
P<username>[\\w+-.#]+)/$']
It implies that that get_absolute_url is passing the pk value of the klass model to the url pattern but it works when I test it manually and it works in literally every other situation.
This...is...a...head scratcher. Any help is appreciated.
UPDATE
I think it might have to do with test isolation. I've done some print debugging and found that each test creates a new instance of the klass model.
Here are my setUp and tearDown methods.
class KlassViewTests(TestCase):
def setUp(self):
self.factory = ClassMateFactory()
self.teacher = self.factory.create_teacher("Maria")
self.linked_student = self.factory.create_student(
"Milhouse",
self.teacher.profile
)
self.klass = self.factory.create_klass(
"Test Klass",
teachers=self.teacher.profile,
students=self.linked_student.profile
)
self.data = {
"name": "New Test Class",
"status": "A",
"students": [self.linked_student.profile.pk],
"teachers": [self.teacher.profile.pk]
}
super().setUp()
def tearDown(self):
print(self.klass.get_absolute_url())
self.teacher.delete()
self.linked_student.delete()
self.klass.delete()
super().tearDown()
Hopefully this helps clear things up.
EDIT
Added the url conf to provide more context
With the current state of your question it looks like a copy paste error. Why I think this:
The error is described by Django as:
django.core.urlresolvers.NoReverseMatch:
Reverse for 'profile' with arguments '('',)' and keyword arguments '{}' not found.
2 pattern(s) tried: ['profile/$', 'profile/(?P<username>[\\w+-.#]+)/$']
You have omitted part of the stack trace so I cannot be sure but the line that causes this error in your code is:
response = self.client.get(self.klass.get_absolute_url())
The model in question seems not to be profile but something called klass.
Seems...
It could also be that self.klass at this point actually refers to a profile (of a teacher or student) and that is why it uses the profile's get_absolute_url.
tl;dr I think you just need to thoroughly read through all of your code (maybe get some second pair of eyes) to find the little mistypings.

How to cache a view method without a route?

I'm trying to test caching in my code. I am using memcached as the backend. I set the CACHE config to use memcached under 'basic'. There isn't a direct route to the get_stuff method. Here is my code:
I have a view that looks like
from .models import MyModel
from django.views.decorators.cache import cache_page
class MyView(TemplateView):
""" Django view ... """
template_name = "home.html"
#cache_page(60 * 15, cache="basic")
def get_stuff(self): # pylint: disable=no-self-use
""" Get all ... """
return MyModel.objects.filter(visible=True, type=MyModel.CONSTANT)
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
stuffs = self.get_stuff()
if stuffs:
context['stuff'] = random.choice(stuffs)
return context
I also have a test that looks like
from django.test.client import RequestFactory
from xyz.apps.appname import views
class MyViewTestCase(TestCase):
""" Unit tests for the MyView class """
def test_caching_get_stuff(self):
""" Tests that we are properly caching the query to get all stuffs """
view = views.MyView.as_view()
factory = RequestFactory()
request = factory.get('/')
response = view(request)
print response.context_data['stuff']
When I run my test I get this error:
Traceback (most recent call last):
File "/path/to/app/appname/tests.py", line 142, in test_caching_get_stuff
response = view(request)
File "/usr/local/lib/python2.7/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/views/generic/base.py", line 87, in dispatch
return handler(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/views/generic/base.py", line 154, in get
context = self.get_context_data(**kwargs)
File "/path/to/app/appname/views.py", line 50, in get_context_data
stuffs = self.get_stuff()
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
result = middleware.process_request(request)
File "/usr/local/lib/python2.7/site-packages/django/middleware/cache.py", line 134, in process_request
if not request.method in ('GET', 'HEAD'):
AttributeError: 'MyView' object has no attribute 'method'
What is causing this and how do I fix this? I'm fairly new to Python and Django.
Can you show the what you have for MIDDLEWARE_CLASSES in settings.py? I looked through the code where your error showed up, and it notes that FetchFromCacheMiddleware must be last piece of middleware in the MIDDLEWARE_CLASSES. I wonder if that is causing your problem.
Related documentation here.
I believe the issue is that the cache_page decorator is meant to be used on view functions, not to decorate methods of class-based views. View functions take 'request' as their first argument, and if you look at the traceback, you can see that in fact the error is caused because the first argument of the function you tried to decorate is not a request but rather 'self' (i.e., the MyView object referred to in the error).
I am not sure if or how the cache_page decorator can be used for class-based views, though this page in the docs suggests a way of using it in the URLconf and I imagine you could wrap the return of ViewClass.as_view in a similar fashion. If the thing you're trying to wrap in caching is not properly a view but rather a utility function of some sort, you should drop to using the more manual lower-level cache API inside of your function (not as a decorator).

Django logout not working

I seem to have the same problem as in this question: Django logout problem
Mine is a bit weirder, it works in google chrome.... but not in firefox...
this is my logout function: (in 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("/")
in settings.py I have:
LOGIN_URL = '/desktop/login/'
LOGOUT_URL = '/desktop/logout/'
LOGIN_REDIRECT_URL = '/'
And in the urls.py of the app iamapps (include in the project urls as /desktop/):
url(r'^login/$', 'iamapps.views.my_login', name='iamapps.login'),
url(r'^logout/$', 'iamapps.views.my_logout', name='iamapps.logout'),
further info:
django 1.4.3 (just updated from 1.3 to 1.4 ....)
python 2.7
works in Chrome but not in Firefox 17.0.1, Linux
The fact that it does work in google chrome but does not work in firefox puzzles me the most. Seems it has something to do with firefox keeps remembering the user as being logged on...
EDIT:
I get a broken pipe.... but I seem to get it not on logging out... but going to the home view after logout....
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
Edit 2
it goes to this view after loging out and being redirected:
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))
I think the redirect with the request to this view causes the problem....
In the log sais it's still user 'michel' (beacuse the view uses the request from the redirect, and that had user michel)... however... user michel is being logged out in the mean time....
EDIT 3
because of the suggestion it's due to the logger.
unremarking the logging does not help
And it's the default logger:
import logging
logger = logging.getLogger(__name__)
EDIT 4 (30-12-2012)
My logout is from a main window where I show a logout link when a user is logged on and a login link if a user is logged out. Also it contains a toolbar, which tools are filled depending on the the user and it's membership of groups.
I think the problem is, it's reloading this main window while the cache and the user in it's request isn't cleared yet. Somehow Chrome knows how to handle this, and firefox results in a broken pipe error. Clearing the cache manually in the browser results in the correct view after reload....
a solution might be to redirect to a page without anything in it that contains users...
or find out to clear the cache on the right moment myselve....
this problem describes maybe the same... but I cannot expect users to do anything in the browser just to logout? see django 1.4 caching GET to /login/
Edit 5 (31-12-2012)
It seems it's a caching problem.... but not sure how to fix this yet.
these are my caching settings:
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',
}
}
But I tried without the dummycache as well
EDIT 6 (4-jan-2013)
Still no solution.... I changed the way I log out to the django way, and I Am using the signals now... see my own answer below.
but still it gives the brokenpipe error which causes firefox stopping logging out. It's not a caching problem. If I go to another page, or even worse... the admin pages. I Am still logged on. The only way to logout is through the logout on the admin page.... If it's not an admin user... there is no way to get me logged out on the firefox browser.
When logging off using the admin interface, so the signal works fine...
I checked by turning off the signal.... and still the logging out in firefox does not work.
Conclusion: going back to the main page () is causing the problem.
EDIT 7 (4 jan 2013)
I made a simple loggedout view for testing,
this template:
<html>
<head>
<title>
Logged out
</title>
</head>
<body>
You are succesfully logged out.<br>
<br>
Go back to the main page
or<br>
log in again
</body>
</html>
and the logged out view:
class LoggedOutView(TemplateView):
template_name = "iamapps/logged_out.html"
and changed the urls in to:
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'),
and still, to simplyfy things... I have the signals turned off.
and it's still not working in firefox.... but it works in chrome
In firefox it does not go to the logged out page
I generally just use the contributed view to logout users. Simply add this to your root urls.py file:
# Would be nice to use settings.LOGIN_URL for `next_page` here, too
url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/login'}),
and you'll be good to go.
Happy Djangoing.
Finally I totally switched to almost back to django defaults...
Using:
in 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)
and urls:
url(r'^login/$', LoginView.as_view(), name='login'),
This solved all my troubles... about loggin and logiing off on...
the login and logout signals just working fine:
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)
browsing to stackoverflow... (did another search)
I found this one: .... see django.contrib.auth.logout in Django ..
But is is even worse.... I found this... astonished... but explains it all:
Django, Logout_URL doesn't redirect well
The I found out it's a won't fix bug (###$%%) not allowed to curse on christmas eve....
So the solution to do my custom stuff is in the signals in stead of using my own view.
Do the default view and redirect...
and use this documentation to create a signal.. https://docs.djangoproject.com/en/dev/topics/auth/#login-and-logout-signals
Adding the signals is quite easy, i put it in models.py off my main app (iamapps):
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)
This works....however it does not solve the broken pipe which I think might cause the failure on the logging out... so logging out in firefox still fails... and in chrome it works...
Logging out from django admin page works in firefox.. and the signal has another pro: also from logging out in the admin interface, the signal is being called...
for logging out i use now this urls.py:
url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='iamapps.logout'),
My suspicion is that the original logout view returns a response that clears cookie or something like that, and you're throwing that response out. Could you try simply returning its response to the user, like this?
def my_logout(request):
# something...
return logout(request)
The verified answer work well for the mentioned version but it is not working in django 2.2 version any more. so in order to do successful redirect after logout you have to define the attributes.
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')),
]
This is how you can see I passed the next_page attribute to the class LogoutView which will tell where to redirect or go after successfull logout.
Hope this may help someone.
Happy Coding!

Django preview, TypeError: 'str' object is not callable

I'm trying to make a Preview function. I'm reading this blog, Django Admin Preview, but now I have the following error and I don't know what it means.
Traceback (most recent call last):
File "/home/user/webapps/django/lib/python2.5/django/core/handlers/base.py", line 92, in get_response
response = callback(request, *callback_args, **callback_kwargs)
TypeError: 'str' object is not callable
I'm lost..
Edit:
Thanks guys/gals, here is my view.py and url.py:
from diligencia.diligencias.views import preview
url(r'^admin/diligencias/diligencia/(?P<object_id>\d+)/preview/$','preview'),
(r'^admin/(.*)', admin.site.root),
from diligencia.diligencias.models import Diligencia
#staff_member_required
def preview(request, object_id):
return object_detail(request, object_id=object_id,queryset=Diligencia.objects.all(), template_object_name = 'diligencia_detail.html', )
The signature for the url function within a urlconf is like this:
def url(regex, view, kwargs=None, name=None, prefix='')
You are using positional parameters only, but are passing only regex, view and name. So Python thinks your third parameter is the kwargs dictionary, not the name.
Instead, do this:
url(r'^admin/diligencias/diligencia/(?P<object_id>\d+)/preview/$', name='preview'),
to pass the name as a kwarg so that Python recognises it properly.
I suspect your view isn't a function. Make sure the argument in your urls.py is a function that takes one parameter. Like :
import default
url(r'^s(?:ite)?/search$', default.search, name="search"),
And then you have in default.py
def search(request) :
# do stuff