2

In my template, login.html, I have:

{% if form.errors %}
    {% if user.is_authenticated %}
    <div class="alert alert-warning"><center>Your account doesn't have access to this utility.</center></div>
    {% else %}
    <div class="alert alert-warning"><center>Incorrect username or password!</center></div>
    {% endif %}
{% endif %}

What I am trying to do is, if after form submission, user is inactive then display a different error message and if user is simply not authenticated then display Incorrect username password error message. This doesn't work. It always displays "Incorrect username or password!" in both the cases. However inside a view, user.is_authenticated returns True even for inactive users.

I there any other wway to get this done? I also tried

{% if 'inactive' in form.errors %}

But this doesnt work too, even though when I try to print form.errors, it shows text "This account is inactive" for inactive users.

EDIT: For view, I am simply using django's login view inside a custom login view

views.py:

from django.contrib.auth.views import login, logout
from django.shortcuts import render, redirect

def custom_login(request, **kwargs):
    if request.user.is_authenticated():
        return redirect('/homepage/')
    else:
        return login(request, **kwargs)
MohitC
  • 4,541
  • 2
  • 34
  • 55

2 Answers2

3

There isn't any point checking {% if user.is_authenticated %} in your login template. If the user is authenticated, then your custom_login view would have redirected them to the homepage.

If the account is inactive, then the form will be invalid and the user will not be logged in. The forms's errors will look like:

{'__all__': [u'This account is inactive.']}

Therefore checking {% if 'inactive' in form.errors %} will not work, because the error is stored with the key __all__, not inactive.

You could do {% if 'This account is inactive.' in form.non_field_errors %} but this is very fragile, and would break if Django ever changed the text of the error message for inactive users.

It would be better to display the actual errors, rather than trying to find out what sort of error it is in the template. The easiest way to display non-field errors is to include:

{{ form.non_field_errors }}

Or, if you need more control:

{% for error in form.non_field_errors %}
    {{ error }}
{% endfor %}

If you need to change the error message for inactive users, you can subclass the authentication form, then use that in your login view.

my_error_messages = AuthenticationForm.error_messages.copy()
my_error_messages['inactive'] = 'My custom message'

class MyAuthenticationForm(AuthenticationForm):
    error_messages = my_error_messages
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • This makes sense, but `request.user.is_authenticated()` in my view is there to redirect user to homepage in case if user is already logged in and trying to access login page. This code does not redirect inactive users to homepage, why? Also why the is_authenticated check wont work in template? – MohitC Oct 12 '16 at 08:52
  • 2
    The authentication form will not log a user in if they are inactive. The form will be invalid with the inactive error message. Since the inactive user is not logged in, `{% if user.is_authenticated %}` will always be `False` in the template. – Alasdair Oct 12 '16 at 08:57
  • 1
    Completely makes sense now. Thanks – MohitC Oct 12 '16 at 08:58
  • I do not get why doesnt simply `{% if 'inactive' in form.non_field_errors %}` doesnt work and I have to check for whole error string? – MohitC Oct 12 '16 at 09:16
  • `form.non_field_errors` is similar to a list `[u'This account is inactive.']`. That list does not contain the string `'inactive'`, therefore `{% if 'inactive' in form.non_field_errors %}` will not work. Python checks whether the list contains the actual string, it does not check whether there are any items in the list that contain the string - that would be something like `any('inactive' in e for e in form.non_field_errors())`, which isn't easy to do in the template. – Alasdair Oct 12 '16 at 09:41
2

Just to complement Alasdair's very sensible answer, if you really want to explicitely check whether the user exists but is inactive, you can use AuthenticationForm.get_user(), ie:

{% if form.errors %}
  {% with form.get_user as user %}
    {% if user %}
       {# the user is inactive #} 
    {% else %}
       {# no user matching username/password #} 
    {% endif %}
  {% endwith %}
{% endif %} 

This is assuming you're using the default django.contrib.auth.forms.AuthenticationForm of course - you can use your own and override the confirm_login_allowed() to implement your own policy.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118