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:
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:
And if we start our development server and go to http://127.0.0.1:8000/ in our browser, we should have this message:
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
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".
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
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.
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.
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>
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>
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)