DEV Community

Stefano Ferrari
Stefano Ferrari

Posted on

Add toast notification with Django - an easy way

I was working on an app with a scheduling feature and I needed a toast notification system to inform users about some deadlines. There are some different ways to achieve this goal.
If you are using Bootstrap, you can use his toast classes and a little bit of JavaScript.

Start the new project

So let's open a new directory in our favourite editor:

VSCode new Django project

Let's create a new venv with
python3 -m venv venv

Activate the new venv. I'm on a linux machine so:
source venv/bin/activate

Install Django:
pip install django

Create our project:
django-admin startproject toast

Move on new directory:
cd toast

And create a new app:
python manage.py startapp toast_notifications

So, now we should have this structure:

VSCode Django structure

And if we start our development server and go to http://127.0.0.1:8000/ in our browser, we should have this message:

Django development server

Now add our app in the settings.py file:


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'toast_notifications',
]
Enter fullscreen mode Exit fullscreen mode

Nice!

Create Models

Now we can create our models. Let's suppose that we need a scheduler to manage equipment maintenance. So we need a model for tools, and in the model.py file of our app we can create it in this way:

class Tool(models.Model):
    tool_code = models.CharField(max_length=10)
    description= models.CharField(max_length=50)    
    serial = models.CharField(max_length=50, null=True, blank=True)          
    note = models.TextField(null=True, blank=True)    
    created_at = models.DateTimeField(auto_now_add=True)

     def __str__(self):        
        return f"Tool Code: {self.tool_code} - Description: {self.description}"
Enter fullscreen mode Exit fullscreen mode

You may need other fields for your tool (i.e. an image or a field to get where the tool is stored...), but for our purpose, those fields are enough.

Now, let's create the model for maintenance:

class Maintenance(models.Model):
    fk_tool = models.ForeignKey(Tool, on_delete=models.CASCADE)
    maintenance_date = models.DateField(null=False, blank=False)
    description= models.CharField(max_length=100)        
    next_schedule = models.DateField(null=False, blank=False)
    note = models.TextField(null=True, blank=True)    
    created_at = models.DateTimeField(auto_now_add=True)

Enter fullscreen mode Exit fullscreen mode

So, we need to put our attention to next_schedule field that will give us the the date for our toast.

Let's migrate our models with:

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

And we should have this structure

vscode django structure

Create views

Now we can create our view. We need to filter our model in order to get only maintenance with next_schedule greater than or equal to today's date. Let's suppose that we need to view in our toasts only the maintenance of the next 30 days.
So, our view could be like this:

from datetime import date, timedelta
from django.shortcuts import render
from .models import *

def home(request):
    today = date.today()
    thirty_days_from_today = today + timedelta(days=30)
    maintenance_scheduler = Maintenance.objects.filter(next_schedule__gte=today).filter(next_schedule__lte=thirty_days_from_today)
    context = {       
        'maintenance_scheduler':maintenance_scheduler
    }
    return render(request, 'toast_notifications/home.html', context)
Enter fullscreen mode Exit fullscreen mode

Now we need to set our templates path in settings.py file in the toast folder. So in the settings.py file we add the directory of templates for our app:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            (BASE_DIR /'toast_notifications' / 'templates'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
Enter fullscreen mode Exit fullscreen mode

Ok. Now in our toast_notifications directory, create new folder "template"; in this folder create new folder "toast_notifications". In this folder create a new file "home.html".

vscode django template structure

Now we need to create our URL path. In urls.py file in toast folder, we can add our path, but first we have to import our view.


from django.contrib import admin
from django.urls import path
from toast_notifications.views import home

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', home, name='home'),
]

Enter fullscreen mode Exit fullscreen mode

So, we are ready for the next step.

Build the template

For the template we can use bootstrap at this link
Bootstrap getting-started

Copy the code in the second step and paste it in your home.html file:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
  </head>
  <body>
    <h1>Hello, world!</h1>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Let's try it. give the command
python manage.py runserver
and if you don't get any errors, you should find your hello world page in the browser.

Bootstrap hello world page

Create some instances

Let'create some instances. In the terminal give the command:
python manage.py shell

and then:
from toast_notifications.models import Tool

Now we can create our Tool instances:

tool1 = Tool.objects.create(tool_code='Code1', description='Description1', serial='Serial1', note='Note1')
tool2 = Tool.objects.create(tool_code='Code2', description='Description2', serial='Serial2', note='Note2')
Enter fullscreen mode Exit fullscreen mode

Same thing for Maintenance instances:
from toast_notifications.models import Maintenance

maintenance1 = Maintenance.objects.create(fk_tool=tool1, maintenance_date='2024-04-23', description='Description 1', next_schedule='2024-04-30', note='Note 1')
maintenance2 = Maintenance.objects.create(fk_tool=tool2, maintenance_date='2024-04-23', description='Description 2', next_schedule='2024-05-30', note='Note 2')
Enter fullscreen mode Exit fullscreen mode

Ok. Now to have a check we can put our instances in our template adding these lines:

<div class="container">
        {% for schedule in maintenance_scheduler %}

            <p>{{ schedule.fk_tool }} - next schedule: {{ schedule.next_schedule }} </p>
        {% endfor %}
    </div>
Enter fullscreen mode Exit fullscreen mode

under the "Hello world" line.

django template with variables
So, we can see only one instance, because of our "thirty_days_from_today" filter. Our toast must show the same result.

Toast

Bootstrap toast component can be found at this link
Bootstrap toasts
You can find different versions based on what you need but toast can be customized as well.

Our toasts could be multiple so we have to put them in a toast container. Moreover, we can loop through our variables to create our toasts.

<div class="toast-container position-fixed bottom-0 end-0 p-3">
    {% for schedule in maintenance_scheduler %}
  <div id="liveToast{{ schedule.pk }}" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="toast-header">

      <strong class="me-auto">Hi! I'm a toast!</strong>
      <small>maintenance scheduler</small>
      <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      {{ schedule.fk_tool }} - next schedule: {{ schedule.next_schedule }}
    </div>
  </div>
  {% endfor %}
</div>
Enter fullscreen mode Exit fullscreen mode

A very little piece of JavaScript

We could have a lot of different needs in order to show our toasts. If we suppose that we need them when we open the page, than we can put on the bottom of our template a very simple script.

script>
        document.addEventListener("DOMContentLoaded", function() {
        var toasts = document.querySelectorAll('.toast');
        toasts.forEach(function(toast) {
            new bootstrap.Toast(toast).show();
        });
});
</script>
Enter fullscreen mode Exit fullscreen mode

With this script, we ask for show our toasts when the DOM content is loaded.

Let's take a look to our whole template:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
  </head>
  <body>


    <h1>Hello, world!</h1>
    <div class="container">
        {% for schedule in maintenance_scheduler %}

            <p>{{ schedule.fk_tool }} - next schedule: {{ schedule.next_schedule }} </p>
        {% endfor %}
    </div>

<div class="toast-container position-fixed bottom-0 end-0 p-3">
    {% for schedule in maintenance_scheduler %}
  <div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="toast-header">

      <strong class="me-auto">Hi! I'm a toast!</strong>
      <small>maintenance scheduler</small>
      <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      {{ schedule.fk_tool }} - next schedule: {{ schedule.next_schedule }}
    </div>
  </div>
  {% endfor %}
</div>




    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

    <script>
        document.addEventListener("DOMContentLoaded", function() {
        var toasts = document.querySelectorAll('.toast');
        toasts.forEach(function(toast) {
            new bootstrap.Toast(toast).show();
        });
});
</script>

  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

bootstrap with toast notification

This is a very simple toast. In my app, toasts are full of other informations, like a URL link to go view the right tool, who is the technician to call and so on.

If you are working with React or Vue for example, you can find other ways to use toasts.

Conclusions

Toasts can be an interesting way to show some information to users. This was a very simple way to use them.
Feel free to drop a suggestion or a comment.
Thanks for reading!

Top comments (0)