Add toast notification with Django - an easy way
Tags: javascript, beginners, django, bootstrap
Published: 2024-04-23 13:48:27

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zo6a29kh56hb98dq76ee.png)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45pz9ufmtt61mwjv8svq.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwhbizhvpsoburlkktru.png)

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',
]
```
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}"
```

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)
    
```

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
```

And we should have this structure


![vscode django structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnmcdrnnj5prx14p9r48.png)


## 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)
```

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',
            ],
        },
    },
]
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvt5xop4xkarjfjt9cvr.png)

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'),
]

```
So, we are ready for the next step.



## Build the template

For the template we can use bootstrap at this link
[Bootstrap getting-started](https://getbootstrap.com/docs/5.3/getting-started/introduction/)

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>
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8b1mycdjhepczdepm4cs.png)
  

## 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')
```

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')
```

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>
```

under the "Hello world" line.

![django template with variables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/di0fb0plipuzn5mq6hwr.png)
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](https://getbootstrap.com/docs/5.3/components/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>
```

## 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>
```
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>
```

![bootstrap with toast notification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rukdb6h9uw3sy9odb49c.png)


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!