Notifying users of various things that happen in your application is super easy to implement. Django Channels notifications allow you to send a message to any user via Email, Datbase, and many other channels.
- Run the pip command to install the latest version:
pip install django-channels-notifications
- Add
django_channels_notifications
to yourINSTALLED_APPS
in settings.py:
INSTALLED_APPS = (
...
'django_channels_notifications',
)
- Run the migration command:
python manage.py migrate
In Django Channels Notifications, each notification is represented by a single class, and to create a new notification you can run the following manage.py command:
python manage.py createnotification TestNotification
And this will place a fresh notification class with the below contents. Each notification class contains a via
method and a variable number of message building methods (such as to_mail
or to_database
) that convert the notification to a message optimized for that particular channel.
from django_channels_notifications.core import Notification
from django_channels_notifications.core.channels import DatabaseChannel
class TestNotification(Notification):
# Get the notification's delivery channels.
def via(self, notifiable):
return [DatabaseChannel]
# Get the dict representation of the notification.
def to_database(self, notifiable):
pass
Notifications may be sent in two ways: using the notify method of the Notifiable mixin or using the NotificationSender . First, let's explore using the mixin:
from django_channels_notifications.core import Notifiable
from django.db import models
class Profile(models.Model, Notifiable):
phone = models.CharField(max_length=255, verbose_name='Phone')
address = models.TextField(max_length=512,verbose_name='Address')
Adding Notifiable
mixin in your Profile
model will allow you to easily send notifications to profiles using notify
method. The notify
method expects to receive a notification instance:
profile = Profile.objects.get(pk=1)
profile.notify(TestNotification());
Remember , you may use the django_channels_notifications.core.Notifiable
mixin on any of your models. You are not limited to only including it on your Profile
model.
Alternatively, you may send notifications via the NotificationSender
. This is useful primarily when you need to send a notification to multiple notifiable entities such as a list of profiles. To send notifications using the NotificationSender, pass all of the notifiable entities and the notification instance to the send
method:
from django_channels_notifications.core import NotificationSender
profiles = Profile.objects.all()
NotificationSender.send(profiles, TestNotification())
Every notification class has a via
method that determines on which channels the notification will be delivered. Notifications may be sent on the database
, mail
, unifonc
channels.
The via
method receives a notifiable
instance, which will be an instance of the class to which the notification is being sent. You may use notifiable
to determine which channels the notification should be delivered on:
#Get the notification's delivery channels.
def via(self, notifiable):
if notifiable.prefers_sms:
return [UnifonicChannel]
return [DatabaseChannel]
Let's quickly go through the different notification channels supported by Django Channels Notifications.
- Database: This option allows you to store notifications in a database should you wish to build a custom UI to display it.
- Mail: The notifications will be sent in the form of email to users.
- Unifonic: As the name suggests, users will receive SMS notifications on their phone.
The DatabaseChannel
notification stores the notification information in a database table. This table will contain information such as the notification type as well as custom JSON data that describes the notification.
If a notification supports being stored in a database table, you should define a to_database
method on the notification class. This method will receive a notifiable
entity and should return a plain Python dict. The returned dict will be encoded as JSON and stored in the data
column of your notifications
table. Let's take a look at an example to_database
method:
# Get the dict representation of the notification.
def to_database(self, notifiable):
return {
'invoice_id': 12,
'amount': 200,
}
Once notifications are stored in the database, you need a convenient way to access them from your notifiable entities. To fetch notifications, you may use the notifications
method. By default, notifications will be sorted by the created_at
timestamp:
profile = Profile.objects.get(pk=1)
for notification in profile.notifications():
print(notification.type)
If you want to retrieve only the "unread" notifications, you may use the unread_notifications
method and If you want to retrieve only the "read" notifications, you may use the read_notifications
method. Again, these notifications will be sorted by the created_at
timestamp:
profile = Profile.objects.get(pk=1)
for notification in profile.unread_notifications():
print(notification.type)
for notification in profile.read_notifications():
print(notification.type)
Typically, you will want to mark a notification as "read" when a user views it. The django_channels_notifications.core.notifiable
mixin provides mark_as_read
and mark_as_unread
methods, which updates the read_at
column on the notification's database record:
profile = Profile.objects.get(pk=1)
# Marking notifications as read
for notification in profile.unread_notifications():
notification.mark_as_read()
# Marking notifications as unread
for notification in profile.read_notifications():
notification.mark_as_unread()
If a notification supports being sent as an email, you should define a to_mail
method on the notification class. This method will receive a notifiable
entity and should return a django.core.mail.EmailMessage
or django.core.mail.EmailMultiAlternatives
instance. Let's take a look at an example to_mail
method:
from django.core.mail import EmailMessage
# Get the mail representation of the notification.
def to_mail(self, notifiable):
return EmailMessage(
'Hello',
'Body goes here',
'from@example.com',
['to1@example.com', 'to2@example.com'],
['bcc@example.com'],
reply_to=['another@example.com'],
headers={'Message-ID': 'foo'},
)
To use the Mailgun provider, you need to add the following parameters to your settings.py
:
EMAIL_HOST = 'smtp.mailgun.org'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'postmaster@msg.com' #please change this with your username
EMAIL_HOST_PASSWORD = '112233445566778899' #please change this with your password
EMAIL_USE_TLS = True
To use the SES provider, you'll need Boto 2.1.0 or higher. Boto is a Python library that wraps the AWS API.
You can do the following to install boto 2.1.0 (we're using --upgrade here to make sure you get 2.1.0):
pip install --upgrade boto
Install django-ses:
pip install django-ses
Add the following to your settings.py:
EMAIL_BACKEND = 'django_ses.SESBackend'
# These are optional -- if they're set as environment variables they won't
# need to be set here as well
AWS_ACCESS_KEY_ID = 'YOUR-ACCESS-KEY-ID'
AWS_SECRET_ACCESS_KEY = 'YOUR-SECRET-ACCESS-KEY'
# Additionally, if you are not using the default AWS region of us-east-1,
# you need to specify a region, like so:
AWS_SES_REGION_NAME = 'us-west-2'
AWS_SES_REGION_ENDPOINT = 'email.us-west-2.amazonaws.com'
The UnifonicChannel
notification allow you to sent the notification as SMS via Unifonic.
You need to add UNIFONIC_APPSID
in settings.py:
UNIFONIC_APPSID = "Your Unifonic APPSID"
If a notification supports being sent as an SMS, you should define a to_unifonic
method on the notification class. This method will receive a notifiable
entity and should return a django_channels_notifications.core.channels.unifonic_channel.UnifonicMessage
instance:
from django_channels_notifications.core.channels.unifonic_channel import UnifonicMessage
# Get the Unifonic representation of the notification.
def to_unifonic(self, notifiable):
return UnifonicMessage().set_body('Your SMS message content').set_recipient(notifiable.phone)
If you would like to send some notifications from a SenderID that is different from the default SenderID in your Unifonic account, you may use the set_sender_id
method on a UnifonicMessage
instance:
from django_channels_notifications.core.channels.unifonic_channel import UnifonicMessage
# Get the Unifonic representation of the notification.
def to_unifonic(self, notifiable):
return UnifonicMessage().set_body('Your SMS message content').set_recipient(notifiable.phone).set_sender_id('Your SenderID')
Django Channels Notifications ships with a handful of notification channels, but you may want to write your own channel to deliver notifications via other channels. Django Channels Notifications makes it simple. To get started, define a class that extended from django_channels_notifications.core.BaseChannel
and contains a send
method. The method should receive two arguments: a notifiable
and a notification
. or by run the following manage.py command:
python manage.py createchannel TestChannel
from django_channels_notifications.core import BaseChannel
class TestChannel(BaseChannel):
# Send the given notification.
def send(self, notifiable, notification):
pass
Once your notification channel class has been defined, you may return the class name from the via
method of any of your notifications:
class TestNotification(Notification):
# Get the notification's delivery channels.
def via(self, notifiable):
return [DatabaseChannel, TestChannel]
# Get the dict representation of the notification.
def to_database(self, notifiable):
pass
# Get the dict representation of the notification.
def to_test(self, notifiable):
pass