Written by Super User.

11- Django User Authentication Login - Logout - Messages

In this Post, we will add user authentication functionality for our Django application. We need to have a url, view and a template for it.

In moviesapp urls.py, create a new path for loginuser.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.moviesapp, name='moviesapp'),
    path('loginuser', views.loginuser, name='loginuser'),
]

 

 In moviesapp views.py, import redirectauthenticate, login and logout. Then create a new view for login.

 If we look at the view below, we are taking form data by using request.POST[] and assign it to variable.

We pass these variables to authenticate method and create an object with the provided username and password data. If this object is not empty, login() uses that object along with HttpRequest object and saves the user’s ID in the session, using Django’s session framework.

from django.shortcuts import render, redirect
from django.http import HttpResponse
from moviesapp.models import MyCustomUser, Movie, UserComment, Watched, Actor
from django.contrib.auth import  authenticate, login, logout


def loginuser(request):
    if request.method == 'POST':
        user_name = request.POST['form_username']
        pass_word = request.POST['form_password']
        userobj= authenticate(request, username= user_name, password=pass_word)
        if userobj is not None:
            login(request, userobj)
            return redirect('moviesapp')
        else:
            return redirect('loginuser')
    else:
        return render(request, 'loginuser.html',{})

 

 

We also need a template (html file) for login in which we display a form for username and password. Create a file named loginuser.html in crmapp's template folder.

 

{% extends 'base.html' %}

{% block title %}
{% endblock title %}

{% block content %}
    <div class="row justify-content-center">
        <div class="col-3">
            <div class="card">
                <div class="card-body">
                <h1 class="text-center">Login</h1>
                    <form method="POST">
                        {% csrf_token %}
                            <div>
                                <input type="text" class="form-control col-sm" placeholder="Enter Username" name="form_username">
                            </div>
                            <div>
                                <input type="password" class="form-control col-sm" placeholder="Enter Password" name="form_password">
                            </div>
                            <div>
                                <button type="submit" class="btn btn-primary">Login</button>
                            </div>
                    </form>

    </div>
{% endblock content %}

 

 

We already created a button for Login on our Navbar but it does not have the url. Lets create it. Open base.html

Change this line:

<a class="btn btn-outline-light" href="#">Login</a>

 

To This: 

<a class="btn btn-outline-light" href="/{% url 'loginuser' %}">Login</a>

 

Restart Apache service.

 

 

 

Django Messages:

If Logon Fails, we are redirected back to loginuser.html. It will be nice if we generate a message for the user if authentication fails.

Open views.py and import messages

Then add messages.success just before the redirect as below. I am using extra_tags to be able to show different colored messages on success or fail.

from django.shortcuts import render, redirect
from django.http import HttpResponse
from moviesapp.models import MyCustomUser, Movie, UserComment, Watched, Actor
from django.contrib.auth import  authenticate, login, logout
from django.contrib import messages


def loginuser(request):
    if request.method == 'POST':
        user_name = request.POST['form_username']
        pass_word = request.POST['form_password']
        userobj= authenticate(request, username= user_name, password=pass_word)
        if userobj is not None:
            login(request, userobj)
            messages.success(request, "Welcome " + user_name, extra_tags='green')
            return redirect('moviesapp')
        else:
            messages.success(request, "Wrong Username or Password", extra_tags='red')
            return redirect('loginuser')
            
    else:
        return render(request, 'loginuser.html',{})

 

Finally we need to modify base.html. We should display the value of messages if there is any. The most proper place to show the message would be right after the Navbar and before the closing </head> tag.

If there is any message for loop will display all the messages and if tags is red the message will be red, if not it will be green

      <!--Navbar Ends Here-->
      <!--Messages Start-->
      <div class="container">
        {% if messages %}
            {% for m in messages%}
                {% if 'red' in m.tags %}
                  <div class="alert alert-danger alert-dismissible fade show" role="alert">
                    <strong>{{m}}</strong>
                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                  </div>
                        

      </div>
                {% else %}
                <div class="alert alert-success alert-dismissible fade show" role="alert">
                  <strong>{{m}}</strong>
                  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                </div>
                {% endif %}
            {% endfor %}
        {% endif %}
    </div>
      <!--Messages Ends-->
  </head>

 

 

 

 

 

 

 

Logout:

For Logout functionality I just need a url, view. 

Add this to crmapp urls.py file

path('logoutuser/', views.logoutuser, name='logoutuser'),

 

And create a view for logout.

def logoutuser(request):
    logout(request)
    messages.success(request, "You are logged out successfully", extra_tags='green')
    return redirect('loginuser')

 

 The navigation bar has the button for Log out but it does not have the link. Let's add it.

<a class="dropdown-item" href="/{% url 'logoutuser' %}">Logout</a>

 

Restart the Apache service and test if everything works properly.