Search code examples
pythondjangodjango-generic-views

Determine whether the user was authenticated in "LogoutView"


Django always show the same page when you go to 127.0.0.1:8000/admin/logout, whether you were logged-in before or not.

What I want is showing a Logout Successful Message only if the user was authenticated before; and show an error message if the user wasn't authenticated and try logging out.

I also need to include the user's first_name in my logout successful message.

I am using class-based django.contrib.auth.views.LogoutView view like this:

class SignoutView(LogoutView):
    template_name = "users/signout.html"

    def get_next_url(self):
        redirect_to = self.request.GET.get("next", "/")
        return redirect_to

and here is the template:

{% extends "base.html" %}
{% block content %}
<h1>Sign out Page</h1>
<br>
{% if was_authenticated %}
<div class="alert alert-success" role="alert">
  <h4 class="alert-heading">You have logged out from your account {{first_name|capfirst}}!</h4>
  <p>Thanks for spending some quality time with my web site today.</p>
  <hr>
  <p class="mb-0" id="displayTimer"></p>
</div>
{% else %}
<div class="alert alert-danger" role="alert">
  <h4 class="alert-heading">Ooh no!</h4>
  <p>Looks like you are not logged in! So you can not log out! Cool yeah?</p>
</div>
{% endif %}
{% endblock %}


{% block js %}
{% if was_authenticated %}
<script type="text/javascript">
var count = 5;
var url = "{{redirect_address}}";
var countdown = setInterval(function() {
  $('#displayTimer').text("You will be redirected to the home page in " + count-- + " seconds...");
  if (count < 0) {
    $('#displayTimer').text("Redirecting....");
    clearInterval(countdown);
    $(location).attr("href", url);
  }
}, 1000);
</script>
{% endif %}
{% endblock %}

I adding extra content to the view like this:

class SignoutView(LogoutView):
    template_name = "users/signout.html"

    def set_extra_context(self):
        return {
            'was_authenticated': self.request.user.is_authenticated,
            'first_name': self.request.user.first_name,
        }

    def get_next_url(self):
        redirect_to = self.request.GET.get("next", "/")
        return redirect_to

but it seems like the function will run after the logout process, so was_authenticated will always be False and first_name always None.

I know how to handle this situation with function-based views, but I rather prefer using class-based views (if possible here!).

Thanks in advance.


Solution

  • Logging the user out is the very first action in the dispatch method. So to capture data from that user, like first name, you'd have to override this method and capture that data before calling logout.

    You could do something like;

    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            self.first_name = request.user.first_name
        return super().dispatch(request, *args, **kwargs)
    

    The line in the source for reference; https://github.com/django/django/blob/master/django/contrib/auth/views.py#L116