Back to Blog
Β·6 min readΒ·Blog

How to set up user notifications for your Django app - Part 1

Notifications provide updates about the activity on an application. In this guide, you will learn how to set up simple notifications for your Django application.

Themba Mahlangu

Themba Mahlangu

How to set up user notifications for your Django app - Part 1

Notifications provide updates about the activity on an application. In this guide, you will learn how to set up simple notifications for your Django application. This is Part 1 of this series.

When you're finished, you'll be able to set up simple notifications for your Django app.

Table of Contents

Tutorials in this series:

Part 1 - Setting up the backend (this tutorial)

Part 2 - Frontend components with TailwindCSS and AlpineJS

Our final product will look something like this.

Prerequisites

To complete this tutorial, you will need:

  • Knowledge of Django
  • Django starter project

In this article we use TailwindCSS (styling) and AlpineJS (javascript)

LEVEL - πŸ’»πŸ’»

Beginner to Intermediate - Knowledge of how Django works, for example how views, URL configuration, and templates work. We will cover high-level concepts but you may need to do further reading on your own.

Key Terms

A Notification or Activity in its simplest form consists of an actor, verb, and object. It describes:

  • action - 'user signed in' performed by an actor - a user on or with an object - email address, or user name

Step 1 - Set up your project

Clone our starter repo here and follow the instructions to set up a new project.

Create a new app called 'notis' in the apps directory.

$ mkdir apps/notis
$ django-admin.py startapp notis
  • Our final folder structure will look like this.
project_name
β”‚   β”œβ”€β”€ config
β”‚   β”‚   β”œβ”€β”€ settings.py
β”‚   β”‚   β”œβ”€β”€ urls.py
β”‚   β”‚   └── ...
β”‚   β”œβ”€β”€ apps
β”‚   β”‚   β”œβ”€β”€ notis
β”‚   β”‚   β”‚   β”œβ”€β”€ models.py
β”‚   β”‚   β”‚   β”œβ”€β”€ apps.py
β”‚   β”‚   β”‚   └── ...
β”‚   β”‚   └── users
β”‚   β”‚       β”œβ”€β”€ signals.py
β”‚   β”‚       └── ...
β”‚   β”œβ”€β”€ templates
β”‚   β”‚   └── ... # see part 2 for this
β”‚   └── manage.py
└── requirements.txt

This structure represents a Django project with a notis app for handling notifications and a users app for handling user-related functionality.

The notis app contains a custom Notification model as described in the document.

The users app contains signal handlers for user login and logout events. The requirements.txt file is at the root of the project and contains the project dependencies, including django-notifications-hq.

The templates directory will be populated in part 2 of the tutorial series.

Install Django Notifications

We will be using the excellent Django notifications library to do some of the heavy lifting for us.

# requirements.txt
# ...
django-notifications-hq==1.6.0
# ...
# settings.py
INSTALLED_APPS = (
    'django.contrib.auth',
    # ...other apps,
    'notifications',
    # ...
)
from django.urls import path, include
import notifications.urls

urlpatterns = [
    # ...
    path('inbox/notifications/', include(notifications.urls, namespace='notifications')),
    # ...
]

Notes

The package will take care of:

  • Setting up a model to store our notifications. The model comes with the basic fields to store information about <actor> <verb> <action_object> <target> <time>.
  • Provides a manager with the required business logic to handle typical actions on notifications e.g. filtering, mark as read etc.
  • Signal dispatcher to simplify creating notifications.
  • Views and template tags to render notifications on your frontend Django templates or single-page app.

Using a custom model for notifications

The above should be sufficient for most apps. However, if you need to customize the notification model in order to extend the functionality you would create a new model:

from django.db import models 
from notifications.base.models import AbstractNotification 

class Notification(AbstractNotification): 
    # custom field example 
    category = models.ForeignKey('myapp.Category', on_delete=models.CASCADE) 

    class Meta(AbstractNotification.Meta): 
        abstract = False

We created a new app called 'notis' to handle extensions to the base library. Technically the model could be added to any other app. This is more organized as it keeps your notifications logic separate from your other apps.

We created a new model and used django's model inheritance to extend an existing model. You will note that we explicitly set abstract = False in the inner Meta class. Django actually does this for you, we have included it here to (hopefully) ignite your curiosity so you can gain a better understanding of how django's model inheritance works.

.. 
NOTIFICATIONS_NOTIFICATION_MODEL = 'apps.notis.Notification'

We are using another model for Notifications. We should update our settings file to reflect this.

Create notifications based on user events

Let's go through an example of how we can use this on a real application to store user sign-in and sign-out events and display them to the user.

A user story is an informal, natural language description of features of a software system (Wikipedia). An example user story for this would be, "as a user, I want to be able to see my sign-in activity".

Breaking it down into actionable tasks

  • a) Listen for a user login or logout actions and store them on the database
  • b) Create frontend component to display notifications (Part 2)
  • c) Connect our frontend component to the backend. (Part 2)

User login or logout events

We need to find a way to get notified when certain actions occur. Fortunately, we don't have to look too far, Django provides a signal dispatcher for just this purpose. You can read more about it here.

Additionally, the Django auth framework already provides prebuilt signals for login and logout actions that our code can listen to.

Setup the signal receivers

from django.contrib.auth import user_logged_in, user_logged_out 
from notifications.signals import notify 
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _

@receiver(user_logged_in) 
def user_signed_in(sender, user, **kwargs): 
    notify.send(user, recipient=user, verb=_("You signed in")) 

@receiver(user_logged_out) 
def user_signed_out(sender, user, **kwargs): 
    notify.send(user, recipient=user, verb=_("You signed out")) 

Notes

We created two receiver functions and connected them to the user_logged_in & user_logged_out signals using the @receiver decorator.

We added business logic to create a notification instance whenever the signal is received. notify.send is a signal provided by the Django-notifications library. The actor recipient is the user.

Behind the scenes, the Django-notifications library will create a notification instance when the signal is dispatched.

Connect the signal receivers

# notis/apps.py
from django.apps import AppConfig

class NotisConfig(AppConfig): 
    name = "apps.notis" 
    def ready(self): 
        try: 
            import apps.notis.signals 
        except ImportError: 
            pass

Signal receivers are connected in the ready() method of your application configuration class. This process happens after the app registration process. See the docs for a more technical explanation.

Conclusion

That’s it for this tutorial. We covered how to set up the backend to handle notifications for our Django app. In the next article, we will create frontend components and connect them to the backend.

Further reading

How to create Django signals - A good article to get the basics of how the dispatch framework works

Activity Streams - Definitions for the terms used in describing a Notification/Activity