Skip to main content

Simple, but rich, declarative notification framework for Django

Project description


Ahem is a notifications framework for Django projects, it uses
declarative style just like Django models.



pip install Ahem

Add it to the list of installed apps in your settings file:

.. code:: python



If you are using ``Celery``, configure the celery beat schedule variable
so periodic tasks can run:

.. code:: python


from ahem.loader import get_celery_beat_schedule
CELERYBEAT_SCHEDULE = get_celery_beat_schedule()

# you may add more periodic tasks after this:
'other-task': {
'task': 'mytasks.the_taks',
'schedule': crontab(...),


| Ahem can be runned both with or without
`celery <>`__. If the celery lib can be
imported, it will try sending notifications asynchronously, else it will
send then in the same thread it was called.
| Periodic notifications will not work without celery.

| **Attention**
| Sending notifications without celery may slow down your system, please
be careful.


To define notifications, create a ```` file in any of
the installed apps of your project and create a class that extends ahem
``Notification`` class.

.. code:: python

# my_django_app/

from datetime import timedelta
from ahem.notification import Notification
from ahem.scopes import QuerySetScope
from ahem.triggers import DelayedTrigger

class MyProjectNotification(Notification):
name = 'my_project'

scope = QuerySetScope()
trigger = DelayedTrigger(timedelta(days=1))

backends = ['email']
templates = {
'default': 'path/to/template.html'}

- ``name`` will be used as the id of your notification, it should be
unique in your project.
- ``scope`` defines which users will receive the notification.
- ``trigger`` defines how and when the notification will be triggered.
- ``backends`` is a list of available backend names for the
- ``templates`` dictionary with templates to be used for each backend.


get\_context\_data(self, user, backend\_name, \*\*kwargs):

You can override ``get_context_data`` to add more variables to the
context. ``User`` is added to context by default, remember to call
``super`` if overriding.

.. code:: python

class TheNotification(Notification):
def get_context_data(self, user, backend_name, **kwargs):
kwargs = super(TheNotification, self).get_context_data(
user, backend_name, **kwargs)
kwargs['extra_context'] = 'This will be shown in the notification'
return kwargs


Currently, ``EmailBackend`` is the only backend available. Developers
are encouraged to build new ones and merge then to this repository via
Pull Request.

Registering users in a backend

Before sending a notification to a user using a specific backend, you
need to register it.

.. code:: python

from ahem.utils import register_user

register_user('backend_name', user,
setting1='username', setting2='secure_key')


- name: ``email``
- settings: no settings required. The ``User`` email will be used.

Context data

- ``subject`` will be used as the email subject.
- ``from_email`` the email the message will be sent from, default is
- ``use_html`` if true, the email will be sent with html content type.

Scheduling a notification

Use the ``schedule`` method to trigger a notification. Use the
``context`` kwarg to pass a context dictionary to the notification.

.. code:: python

# this will trigger the notification according to it's `trigger`
# for the MyProjectNotification, it will wait 1 day before sending
# the notification.
MyProjectNotification.schedule(context={'some_param': 'value'})

Overriding backends

You can also limit the backends that will be used by passing a list to
the ``backends`` kwarg.

**Since the EmailBackend is currently the only one available, this
feature is currently useless**

.. code:: python


Overriding trigger

You can also explicitly tell when the notification should be sent by
passing ``delay_timedelta`` or ``eta``.

.. code:: python

# Notification will be sent at 23:45
from celery.schedules import crontab
MyProjectNotification.schedule(eta=crontab(crontab(hour=23, minute=45)))

# Notification will be send 20 minutes after it was scheduled
from datetime import timedelta


Scopes are a declarative way to select which users will receive the
notification when it's executed. Ahem comes with 2 scopes by default,
but if you are feeling adventurous you can build your onw one.


``QuerySetScope`` will return all users if no argument is passed but you
can pass a queryset to filter only the ones you desire.

.. code:: python

from ahem.scopes import QuerySetScope

class TheNotification(Notification):
scope = QuerySetScope(User.objects.filter(is_staff=True))

This will scope the notification only to staff users.


``ContextFilterScope`` filters the ``User`` model according to a param
specified in the context passed to the notification when it's scheduled.

.. code:: python

from ahem.scopes import ContextFilterScope
class TheNotification(Notification):
scope = ContextFilterScope(
context_key='user_is_admin', lookup_field='is_admin')

# This will send the notification only to non admin users
TheNotification.schedule(context={'user_is_admin': False})

filter\_scope(self, queryset, context)

Extra filters can be performed in the ``Notification`` ``scope`` by
adding a ``filter_scope`` method to your notification. This method
should return a list of ``User``\ s

.. code:: python

# This will restrict the notification to users with `first_name` "Camila"
class TheNotification(Notification):
scope = QuerySetScope(User.objects.filter(is_staff=True))

def filter_scope(self, queryset, context):
return queryset.filter(first_name='Camila').all()


Triggers define when notifications will be send. Currently the two types
of triggers available are: ``DelayedTrigger`` and ``CalendarTrigger``,
but you can also write custom ones by extending ``NotificationTrigger``.


``DelayedTrigger``\ s should receive a timedelta as their first param.
This will specify how long should be waited before sending the
notification. If a timedelta is not specified, the notification will be
imediately sent. You can optitionaly pass ``at_hour`` and/or
``at_minute`` kwargs. By doing this, after timedelta is added to the
current time, the hour and minute will be overwriten to the ones you

.. code:: python

from datetime import timedelta
from ahem.triggers import DelayedTrigger

# Will send 2 days after scheduled at 18:00.
class TheNotification(Notification):
trigger = DelayedTrigger(timedelta(days=2), at_hour=18, at_minute=0)


``CalendarTrigger`` are periodic notifications, use ``Celery``
``crontab`` to define it's periodicity. See ``Celery`` documentation for
more info:

.. code:: python

from celery.schedules import crontab
from ahem.triggers import CalendarTrigger

# Will send notifications everyday at midnight
class TheNotification(Notification):
trigger = CalendarTrigger(crontab(hour=0, minute=0))


``templates`` specify which template should be used to render
notification content. There should be at least a ``default`` template,
but you can specify a different one for each backend. When rendering the
template, all context variables will be available.

.. code:: python

class TheNotification(Notification):
templates = {
'default': 'path/to/your/template.html',
'email': 'path/to/email/template.html'}


Use ``tox`` to run tests.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

Ahem-0.2.1.tar.gz (9.1 kB view hashes)

Uploaded source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page