Django - Render view on user_logged_out signal - django

I would like to be able to render a different logged out template when the user_logged_out signal is fired. I can catch the signal and check for my condition correctly, and I have a view with a named URL that works just fine, but I can't seem to render the view.
I've tried each of these, with both a class based and functional view, but can't get them to work. Using ipdb I can get a template to render in the console, but can't figure out the right way to return it/call the view to have it returned. Thoughts?
#receiver(user_logged_out)
def my_logged_out_signal_handler(sender, request, user, **kwargs):
if user.has_condition:
# tried this
resolve(reverse('my_named_url', kwargs={'kwarg1': 'something'})).func(request, something)
# and this
render_to_response(resolve(reverse('my_named_url', kwargs={'kwarg1': something})).func(request, kwarg1=something).render())
# and this
render(MyClassView.as_view()(request, kwarg1=something))
# and this
return (resolve(reverse('my_named_url', kwargs={'kwarg1': something})).func(request, kwarg1=something).render())
# and this
return HttpResponse(resolve(reverse('my_named_url', kwargs={'kwarg1': something})).func(request, kwarg1=something).render())

A signal handler is not a view, it cannot render/return a response.
You could simply handle logic in your own view, and call or redirect to the auth logout function from there. Something like below..
from django.shortcuts import redirect
def my_logout(request):
kwargs = {}
if my_condition:
kwargs['template_name'] = 'my_template.html'
kwargs['extra_context'] = ...
return redirect('logout', **kwargs)

Found a clever solution allowing a redirect from anywhere, if you really need to. https://djangosnippets.org/snippets/2541/

Related

How to call an auth view from another view?

I want to execute a custom logic block in a view before the PasswordResetView is called. This is what I am trying to do, which of course always fails regardless the code, I must be taking a non adequate route to achieving this. I need to save some information, do some internal notifications and only call the password reset view if a condition is met.
views.py
from django.contrib.auth.views import PasswordResetView
def user_password_reset(request):
# Do something here before loading the passwordresetview
# Logic here
return PasswordResetView.as_view(template_name = 'account/password_reset_form.html',
email_template_name='account/password_reset_email.html',
html_email_template_name='account/password_reset_email.html',
success_url = reverse_lazy('account:password_reset_done'))
Which is the standard way of achieving this?
Many thanks in advance.
You can call the function that is returned by the .as_view():
from django.contrib.auth.views import PasswordResetView
def user_password_reset(request):
# Do something here before loading the passwordresetview
# Logic here
return PasswordResetView.as_view(
template_name='account/password_reset_form.html',
email_template_name='account/password_reset_email.html',
html_email_template_name='account/password_reset_email.html',
success_url = reverse_lazy('account:password_reset_done')
)(request)
That being said, it might make more sense to just subclass the PasswordResetView, and for example overwrite the .dispatch(..) method.

How can I send data from the get_avatar() (Google Sign In) to my template?

I have integrated Google Sign In using social_django app although in order to get the profile photo / avatar of the user I have used get_avatar through django pipeline. Now the problem is that how can I send the url received in the get_avatar function to one of my templates?
I have tried using Render, HTTPResponse, HTTPResponseRedirect, JSONResponse but I'm not getting the desired results.
get_avatar():
def get_avatar(backend, strategy, details, response,
user=None, *args, **kwargs):
if backend.name == 'google-oauth2':
try:
url = response["picture"]
except KeyError:
url = response['image'].get('url')
The rendering of get_avatar function returns a empty dictionary to the template. Rather it should return the URL which we get from get_avatar function.
Thanks in advance :)

Django Testing - check messages for a view that redirects

I have been writing tests for one of my django applications and have been looking to get around this problem for quite some time now. I have a view that sends messages using django.contrib.messages for different cases. The view looks something like the following.
from django.contrib import messages
from django.shortcuts import redirect
import custom_messages
def some_view(request):
""" This is a sample view for testing purposes.
"""
some_condition = models.SomeModel.objects.get_or_none(
condition=some_condition)
if some_condition:
messages.success(request, custom_message.SUCCESS)
else:
messages.error(request, custom_message.ERROR)
redirect(some_other_view)
Now, while testing this view client.get's response does not contain the context dictionary that contains the messages as this view uses a redirect. For views that render templates we can get access to the messages list using messages = response.context.get('messages'). How can we get access messages for a view that redirects?
Use the follow=True option in the client.get() call, and the client will follow the redirect. You can then test that the message is in the context of the view you redirected to.
def test_some_view(self):
# use follow=True to follow redirect
response = self.client.get('/some-url/', follow=True)
# don't really need to check status code because assertRedirects will check it
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, '/some-other-url/')
# get message from context and check that expected text is there
message = list(response.context.get('messages'))[0]
self.assertEqual(message.tags, "success")
self.assertTrue("success text" in message.message)
You can use get_messages() with response.wsgi_request like this (tested in Django 1.10):
from django.contrib.messages import get_messages
...
def test_view(self):
response = self.client.get('/some-url/') # you don't need follow=True
self.assertRedirects(response, '/some-other-url/')
# each element is an instance of django.contrib.messages.storage.base.Message
all_messages = [msg for msg in get_messages(response.wsgi_request)]
# here's how you test the first message
self.assertEqual(all_messages[0].tags, "success")
self.assertEqual(all_messages[0].message, "you have done well")
If your views are redirecting and you use follow=true in your request to the test client the above doesn't work. I ended up writing a helper function to get the first (and in my case, only) message sent with the response.
#classmethod
def getmessage(cls, response):
"""Helper method to return message from response """
for c in response.context:
message = [m for m in c.get('messages')][0]
if message:
return message
You include this within your test class and use it like this:
message = self.getmessage(response)
Where response is what you get back from a get or post to a Client.
This is a little fragile but hopefully it saves someone else some time.
I had the same problem when using a 3rd party app.
If you want to get the messages from a view that returns an HttpResponseRedict (from which you can't access the context) from within another view, you can use get_messages(request)
from django.contrib.messages import get_messages
storage = get_messages(request)
for message in storage:
do_something_with_the_message(message)
This clears the message storage though, so if you want to access the messages from a template later on, add:
storage.used = False
Alternative method mocking messages (doesn't need to follow redirect):
from mock import ANY, patch
from django.contrib import messages
#patch('myapp.views.messages.add_message')
def test_some_view(self, mock_add_message):
r = self.client.get('/some-url/')
mock_add_message.assert_called_once_with(ANY, messages.ERROR, 'Expected message.') # or assert_called_with, assert_has_calls...

Django - Ajax registration

I am trying to allow registration (using this django-registration register view) to one of my applications from a modal dialog.
Since this form is in a modal box, I'd like to get an json reponse on success (instead of the default redirection)
How can I use this view (django-registration register) to manage the registration and send back a json response on success ?
I know how to make ajax/json responses, the question is how to use the django-registration view without the redirection behavior or wrap it into an other view to manage the response.
First you need to change the urls.py to wrap the existing view with another functionality. To do that you have to create a new backend package in backends folder and change urls.py there while keeping everything else intact, or you could just go ahead and modify the existing urls.py in the backend package.
I have not tested this, but it should work.
Point url to the new view:
# urls.py
url(r'^register/$', register_wrap,
{'backend': 'registration.backends.default.DefaultBackend'},
name='registration_register'),
# your new view that wraps the existing one
def register_wrap(request, *args, **kwargs):
# call the standard view here
response = register(request, *args, **kwargs)
# check if response is a redirect
if response.status_code == 302:
# this was redirection, send json response instead
else:
# just return as it is
return response
If you are going to need this for more views you can just create a decorator using this.
Why I would do is to check if request.is_ajax() in your normal after-successfull-registration-redirect view and return json response there.
You ask how you can use the existing view to manage the registration and send back a json response on success. Since the HttpResponseRedirect is pretty much hard coded in the view, you can't use the view as it is. Instead, either fork it, or write your own view and change the urls.py so that r'^register/$' directs to your new view.
As far as the json response is concerned, on success you can do something like this:
from django.utils import simplejson as json
def register_ajax(request):
...
return HttpResponse(json.dumps(dict(success=True, **dict_containing_data)))
Hope this helps

Django No redirections

I have a flash file which calls a url like: http://test.com/savethis/123456/
I just want my view to save "123456" in the database and return nothing.
After saving the values what do I do? If I redirect it it changes the page and that's bad. I could render a page, but I don't want to. I just want it to end and not throw any errors.
Make sure your URLConf points to your desired view function, and write something like:
from django.http import HttpResponse
from my_models import MyModel
def myview(request, number):
my_model = MyModel(my_field = number)
my_model.save()
return HttpResponse()
The empty HttpResponse at the end there sends back a status code of 200 OK so that the browser or other server that connects to your endpoint knows the request was completed.
It sounds like you're in a view function, which means someone's issued an HTTP request for something, which you have to respond to, so you can't just do nothing.
Either return an error code, or return an HttpResponse. You could just return an empty OK response (i.e. return HTTP response 200):
from django.http import HttpResponse
def myview(request):
return HttpResponse()