Grocery Bag using Django (Part-3) - User Authentication
Tags: webdev, python, django
Published: 2021-11-29 05:02:01

---
title: Grocery Bag using Django (Part-3) - User Authentication
published: true
series: Grocery Bag Application Using Django
date: 2021-11-28 07:38:46 UTC
tags: webdev, Python, Django
canonical_url: http://iread.ga/posts/71/grocery-bag-using-django-part-3-user-authentication
---

# **Introduction**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gp6tzx2wdulbmchds8p0.png)

In the [previous blog](https://iread.ga/posts/70/grocery-bag-using-django-part-2-fixing-templates-and-static-files), we had learned about Template Inheritance and how to serve static files. We had fixed our templates also. In this blog, we'll see how we can authenticate the user into our web app.

To keep it simple, we would not be using custom authentication. Instead, we'll be using Django's User model, which will make our task quite easier. Let's get started!  
 

# **Alerts**

Quite commonly in the upcoming sections, we need to display a one-time notification message (also known as “flash message”) to the user after processing a form or some other types of user input. For this, Django provides full support for cookie- and session-based messaging, for both anonymous and authenticated users. The messages framework allows us to temporarily store messages in one request and retrieve them for display in a subsequent request (usually the next one). Every message is tagged with a specific `level` that determines its priority (e.g., `info`, `warning`, or `error`).

Django template language has an `include` tag. `include` tag loads a template and renders it with the current context. This is a way of “including” other templates within a template. The template name can either be a variable or a hard-coded (quoted) string, in either single or double quotes.

Let's create a folder called `partials` inside the `templates` folder and within the `partials` folder, create a `alerts.html` file and add the following code:

```html
{% if messages %} 
    {% for message in messages %} 
        {% if message.tags == 'error' %}
            <div class="alert alert-danger alert-dismissible fade show" role="alert">
            {{message}}
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
            </div>
        {% else %}
            <div class="alert alert-{{message.tags}} alert-dismissible fade show" role="alert">
            {{message}}
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
            </div>
        {% endif %}
    {% endfor %} 
{% endif %}

```

We are using [Bootstrap dismissable alerts](https://getbootstrap.com/docs/5.1/components/alerts/#dismissing) for the alerts. We are iterating over the messages passed from the view functions and showing them as per their categories. Even if there is only one message, we should still iterate over the `messages` sequence, because otherwise the message storage will not be cleared for the next request. Note that we are using an if condition to check if the `message.tag` is error, then we are showing danger alert, else we are directly showing the alerts using the `message.tag`. This is because, in Bootstrap we have **danger** class, but Iin Django we have **error** tag.  
 

# **Registering New User**

The first thing we wish to do is to register a new user. Whenever a user comes to the signup page, he is requested to enter a username and password. If the username is not already in the database, the user is created and redirected to the login page. If there is already a user present with the same username, an error message is flashed.

Since, this is an authentication related task, open the `accounts/views.py` file and add the following code:

```py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.models import User

def signup(request):
    if request.user.is_authenticated:
        return redirect('index')
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username and password:
            try:
                User.objects.get(username=username)
                messages.error(request, 'User already exists')
            except User.DoesNotExist:
                User.objects.create_user(username=username, password=password)
                messages.success(request, 'Signup success')
                return redirect('signin')
        messages.error(request, "Username or Password is missing!")
    return render(request, 'signup.html')
```

In the above script, first we are checking if the user is already authenticated. If it is, we redirect it to the index page. Then we are checking, if the user has entered username and password or not. If not, we flash an error message saying  **Username or Password is missing!**. Then we check if the user is already present in the database.  If it is, we again flash an error saying **User already exists**. Else, the user is created and redirected to the login page.

Now we need to create a URL route for this view function in the `accounts/urls.py` file:

```py
from django.urls import path

from accounts.views import signup

urlpatterns = [
    path('signup', signup, name='signup'),
]

```

Now that we have a view function to handle the signup functionality and a URL route is attached to it, we are ready to make changes in the signup form. Open the `templates/signup.html`, and add the following code:

```html
{% extends "base.html" %}{% load static %} {% block title %} Sign Up {% endblock title %} 

{% block custom_head %}
<link rel="stylesheet" href="{% static 'css/signin.css' %}" />
{% endblock custom_head %} 

{% block content %}
<body class="text-center">
  <main class="form-signin">
    <form method="POST" action="{% url 'signup' %}">
      {% csrf_token %}
      
      <h1 class="h3 mb-3 fw-normal">Please sign up</h1>
      {% include 'partials/alerts.html' %}
      <div class="form-floating mt-2">
        <input
          type="text"
          class="form-control"
          id="floatingInput"
          name="username"
          placeholder="johndoe"
        />
        <label for="floatingInput">Username</label>
      </div>
      <div class="form-floating mt-2">
        <input
          type="password"
          class="form-control"
          id="floatingPassword"
          name="password"
          placeholder="Password"
        />
        <label for="floatingPassword">Password</label>
      </div>

      <button class="w-100 btn btn-lg btn-primary" type="submit">
        Sign up
      </button>
      <p class="mt-3">
        Already Registered? <a href="{% url 'signin' %}">Sign in now</a>
      </p>
    </form>
  </main>
</body>
{% endblock content %}

```

The first change we are making is in the form tag. The form **method** is set to `POST` and the **action** URL is the signup route we just created. Also we are adding the URL of the sign in page in the Already Registered? line. We haven't created this route yet.  
 

# **User Login**

Next, we have to create the login functionality. Inside the accounts/views.py file, add the following view function.

```py
from django.contrib.auth import authenticate, login

def signin(request):
    if request.user.is_authenticated:
        return redirect('index')

    redirect_url = request.GET.get('next')
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username and password:
            user = authenticate(username=username, password=password)
            if user:
                login(request, user)
                if redirect_url:
                    return redirect(redirect_url)
                return redirect('index')
            else:
                messages.error(request, 'Incorrect username or password!')
                return redirect(f'/accounts/signin?next={redirect_url}')
        messages.error(request, "Username or Password is missing!")
    return render(request, 'signin.html')
```

This view function is quite similar to the signup function. The change we are making here is, we are using the authenticate function to check if the user exists in the database or not. If not, we show an error message and redirect the user to the same login page. If the user exists, we login the user. Then we check if there is a next route in the URL. If it's there, we redirect the user to that page, else to the index page. The next parameter tells that what page should the user be redirected to.

Now lets create a URL for this function in the `accounts/urls.py` file:

```py
from django.urls import path

from accounts.views import signin, signup

urlpatterns = [
    path('signup', signup, name='signup'),
    path('signin', signin, name='signin'),
]

```

The final change we need to make, is in the `signin.html` file:

```html
{% extends "base.html" %}{% load static %} {% block title %} Sign In {% endblock title %} 

{% block custom_head %}
<link rel="stylesheet" href="{% static 'css/signin.css' %}" />
{% endblock custom_head %} 

{% block content %}
<body class="text-center">
  <main class="form-signin">
    <form method="POST" action="{% url 'signin' %}{% if request.GET.next %}?next={{request.GET.next}}{% endif %}">
      {% csrf_token %}

      <h1 class="h3 mb-3 fw-normal">Please sign in</h1>
      {% include 'partials/alerts.html' %}
      <div class="form-floating mt-2">
        <input
          type="text"
          class="form-control"
          id="floatingInput"
          name="username"
          placeholder="johndoe"
        />
        <label for="floatingInput">Username</label>
      </div>
      <div class="form-floating mt-2">
        <input
          type="password"
          class="form-control"
          id="floatingPassword"
          name="password"
          placeholder="Password"
        />
        <label for="floatingPassword">Password</label>
      </div>

      <button class="w-100 btn btn-lg btn-primary" type="submit">
        Sign in
      </button>
      <p class="mt-3">New user? <a href="{% url 'signup' %}">Sign up now</a></p>
    </form>
  </main>
</body>
{% endblock content %}

```

Everything is similar here. But the action URL has a little change. If the request URL has a next parameter, we add that parameter in the action URL.  
 

# **Logging Out User**

The only thing we are left with is to log out the user.

```py
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required

@login_required
def signout(request):
    logout(request)
    messages.info(request, "Logged out!")
    return redirect('signin')

```

We have used a `@login_required` decorator so that only authenticated users can logout. Let's add this view function in the urls.

```py
from django.urls import path

from accounts.views import signin, signout, signup

urlpatterns = [
    path('signup', signup, name='signup'),
    path('signin', signin, name='signin'),
    path('signout', signout, name='signout'),
]

```

Also add the line in the `settings.py` file:

```py
LOGIN_URL = '/accounts/signin'
```

Also, we need to add Logout button in the index page. Open the `index.html` file and add:

```html
{% extends "base.html" %}{% load static %} {% block title %}View Bag{% endblock title %} 

{% block content %}
<body>
  <div class="container mt-5">
    <!-- top -->
    <div class="row">
      <div class="col-lg-6">
        <h1>View Grocery List</h1>
      </div>
      <div class="col-lg-6 float-right">
        <div class="row">
          <div class="col-lg-6">
            <!-- Date Filtering-->
            <input type="date" class="form-control" />
          </div>
          <div class="col-lg-4">
            <input type="submit" class="btn btn-danger" value="filter" />
          </div>
          <div class="col-lg-2">
            <p class="mt-1"><a href="{% url 'signout' %}">Log Out</a></p>
          </div>
        </div>
      </div>
    </div>
    <!-- // top -->
    <!-- Grocery Cards -->
    <div class="row mt-4">
      <!--- -->
      <!-- Loop This -->
      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Tomato</h5>
            <h6 class="card-subtitle mb-2 text-muted">2 Pcs.</h6>
            <p class="text-success">BOUGHT</p>
          </div>
        </div>
      </div>
      <!-- // Loop -->
      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Chicken</h5>
            <h6 class="card-subtitle mb-2 text-muted">2Kgs</h6>
            <p class="text-danger">NOT AVAILABLE</p>
          </div>
        </div>
      </div>

      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Posto</h5>
            <h6 class="card-subtitle mb-2 text-muted">50gms</h6>
            <p class="text-info">PENDING</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
{% endblock content %}

```

 

# **User Authorisation**

We'll make the index page available to the authenticated users only. If the user is not authenticated, it is redirected to the `LOGIN_URL`. 

```py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required

# Create your views here.

@login_required
def index(request):
    return render(request, "index.html")
```

# **Database Migrations**
Now that we have done everything, we are ready to run the database migrations:

```bash
$ python manage.py makemigrations
$ python manage.py migrate 
```

# **Demo Video**

Watch the demo video here: 
{% vimeo 650755180 %}

#   
**Conclusion**

In this part we have seen how we can authenticate users, and how we can restrict users from accessing certain pages. In the next part, we'll work on the CRUD operations. Stay tuned!

Code till now: [https://github.com/ashutoshkrris/Grocery-Bag/tree/blog3](https://github.com/ashutoshkrris/Grocery-Bag/tree/blog3)