Getting Started

Installation

Getting the code

The recommended way to install django-vox is via pip (on Windows, replace pip3 with pip)

$ pip3 install django-vox[markdown,twilio,html]

Configuring Django

Add "django_vox" to your INSTALLED_APPS setting:

INSTALLED_APPS = [
    # ...
    "django_vox",
]

Additionally, you may want to configure certain backends depending on exactly what sort of other notifications you want.

The Demo

While you’re welcome to use the setup instructions here, it may be easier to just try out the demo that comes with this package. The demo doesn’t cover all the use cases (yet) but it does cover most of the standard stuff.

Registering the Models

The process of issuing and routing notifications in Django Vox happens in 4 steps.

  1. Notification definitions: These definitions are registered, and attached to specific models.
  2. Recipients: Any given notification can have 4 possible recipients.
    1. The model that the notification is attached to
    2. The actor of the notification (optional)
    3. The target of the notification (optional)
    4. The site contacts (these come built-in)
  3. Channels: Additionally, each of these recipients can have zero, 1, or multiple “channels”. For example, a User model might have one channel for the user themselves, one for the user’s followers, and one for the user’s emergency contact.
  4. Contact: A contact specifies the actual address that a the notifications are sent to. Any model specified in a channel, should also define contacts in its registration, otherwise that recipient won’t have any way of receiving the notifications.

Any model that will be either issuing notifications, or receiving them should have a registration. It might look something like this:

from django.db import models
from django_vox.registry import (VoxRegistration, Notification,
                                 Channel, objects, provides_contacts)

class User(models.Model):

    # required email, optional mobile_phone
    email = models.EmailField(blank=False)
    mobile_phone = models.CharField(blank=True, max_length=50)
    ...


class UserVox(VoxRegistration):


    @provides_contacts("email")
    def email_contact(self, instance, notification):
        yield instance.email

    @provides_contacts("sms")
    def email_contact(self, instance, notification):
        if instance.mobile_phone:
            yield instance.mobile_phone

    def get_channels(self):
        return {"": Channel.self(self)}

class PurchaseOrder(models.Model):

    customer = models.ForeignKey(User, on_delete=models.PROTECT)

    def save(self, *args, **kwargs):
        created = self.id is None
        if not created:
            old = PurchaseOrder.objects.get(pk=self.pk)
        else:
            old = None
        super().save(*args, **kwargs)
        objects[type(self)].registration.post_save(
            created, old, self)


class PurchaseOrderVox(VoxRegistration):

    received = Notification(
        _("Notification that order was received."))
    on_hold = Notification(
        _("Notification that order is on hold."))

    def post_save(self, created, old, new):
        if created:
            self.received.issue(new)
        if old and not old.on_hold and new.on_hold:
            self.on_hold.issue(new)

    def get_channels(self):
        return {"cust": Channel.field(PurchaseOrder.customer)}

# the actual registration
objects.add(User, UserVox, regex=None)
objects.add(PurchaseOrder, PurchaseOrderVox, regex=None)

In the above example, you have a User model, which can receive emails, and optionally an SMS message. You also have purchase orders that have two notifications registered on them (received and on_hold). Whenever the purchase order is saved, it calls post_save on the registration object, and that fires the notifications themselves.

Once you’ve finished adding these, you’ll need to regenerate the notifications table using the make_notifications management command:

python3 manage.py make_notifications

And there you have it. Now, in order for this to do anything useful, you’ll need to add some appropriate templates. In this case, you’ll want an email template for the “customer” recipient of the purchase order notifications, and possibly a template for a site contact too.

For more details on model registration and the various options, see the Registrations in Detail page.

One-time Messages from the Admin

The normal way to handle notifications is call notification.issue(instance) from within the code. It’s also possible to manually issue notifications from the admin as long as a notification doesn’t have an actor/target model. The other way of sending messages completely bypasses the Notification models and uses an Admin Action.

In order to send messages this way, you need to add the django_vox.admin.notify action to your ModelAdmin class. It might look something like this:

from django.contrib import admin
from django_vox.admin import notify

class UserAdmin(admin.ModelAdmin):
    actions = (notify, )

admin.site.register(YourUserModel, UserAdmin)

In order for this to work right, the model in question is treated as the channel, and so needs to have contacts registered for the appropriate backend & protocol that you want to use.

Note

Because we don’t actually have a notification model here, a fake notification (django_vox.models.OneTimeNotification) is passed to the contact methods. This can be used if only want certain contacts to be accessible in this way.