Skip to main content

GitHub notifications alike app for Django with expo push notifications

Project description

Fork of django-notifications with some additional features

Requirements

  • Django >= 3.8 *
  • Python >= 3.8 *
  • djangorestframework >= 3.13
  • django-model-utils >= 3.1.0
  • jsonfield >= 2.1.0
  • pandas >= 2.2.0
  • requests >= 2.30

Add notifications app to INSTALLED_APPS in your django settings.py:

INSTALLED_APPS = (
    ...,
    "django.contrib.staticfiles",
    "rest_framework",  # required only if using the provided REST endpoints
    'notifications',    # Add this line
     ...,
)

General ViewSets endpoints added (with custom serializer):

  • GET /api/notifications/ : Get all notifications for the current user
  • POST /api/notifications/read-all/ : Mark all notifications as read for the current user
  • GET /api/notifications/int:pk/ : Get a notification by id and mark it as read

Cron for deleting old notifications

You can set up a cron job to delete old notifications automatically.

Add the following to your settings.py :

DJANGO_NOTIFICATIONS_CONFIG = {
    'AUTO_DELETE_NOTIFICATIONS': True,
    'NOTIFICATIONS_DELETE_DAYS': 30, # Number of days to keep notifications (default is 30)
}

CRONJOBS = [
    ('0 0 * * *', 'notifications.cron.delete_old_notifications'), # Delete old notifications every day at midnight
]

In your MY_APPS settings, add the following:

MY_APPS = [
    'notifications',   # Library for notifications
    'django_crontab',  # Library for cron jobs
]

Finally, this commands are needed to enable the cron job.

pip install django-notifications-pro[cron]
service cron start
python manage.py crontab add

Expo notifications

You will be able to register devices, and each time a notification is sent, it will be delivered through Expo Go Notifications.

This install is needed to enable expo notifications.

pip install django-notifications-pro[expo]

Add the following to your settings.py :

DJANGO_NOTIFICATIONS_VIEWS = {
    'USE_EXPO_NOTIFICATIONS': True, # Set to True to enable expo notifications
    'EXPO_APP_ID': '<your-expo-app-id>', 
}

Then run the migrations:

python manage.py makemigrations
python manage.py migrate

Urls

Expo Notifications

  • POST /api/expo-devices/register-device/ : Register a device to receive expo notifications
  • POST /api/expo-devices/unregister-device/ : Unregister a device to stop receiving expo notifications

Contributing

Maintained and developed by Linkchar Software Development.

Original django-notifications Documentation

build-status Coverage Status

django-notifications is a GitHub notification alike app for Django, it was derived from django-activity-stream

The major difference between django-notifications and django-activity-stream:

  • django-notifications is for building something like Github "Notifications"
  • While django-activity-stream is for building Github "News Feed"

Notifications are actually actions events, which are categorized by four main components.

  • Actor. The object that performed the activity.
  • Verb. The verb phrase that identifies the action of the activity.
  • Action Object. (Optional) The object linked to the action itself.
  • Target. (Optional) The object to which the activity was performed.

Actor, Action Object and Target are GenericForeignKeys to any arbitrary Django object. An action is a description of an action that was performed (Verb) at some instant in time by some Actor on some optional Target that results in an Action Object getting created/updated/deleted.

For example: justquick (actor) closed (verb) issue 2 (action_object) on activity-stream (target) 12 hours ago

Nomenclature of this specification is based on the Activity Streams Spec: http://activitystrea.ms/specs/atom/1.0/

Requirements

  • Python 3.7, 3.8, 3.9, 3.10, 3.11
  • Django 3.2, 4.0, 4.1

Installation

Installation is easy using pip and will install all required libraries.

$ pip install django-notifications-hq

or get it from source

$ git clone https://github.com/django-notifications/django-notifications
$ cd django-notifications
$ python setup.py sdist
$ pip install dist/django-notifications-hq*

Note that django-model-utils will be installed: this is required for the pass-through QuerySet manager.

Then to add the Django Notifications to your project add the app notifications to your INSTALLED_APPS and urlconf.

The app should go somewhere after all the apps that are going to be generating notifications like django.contrib.auth

INSTALLED_APPS = (
    'django.contrib.auth',
    ...
    'notifications',
    ...
)

Add the notifications urls to your urlconf:

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

To run schema migration, execute python manage.py migrate notifications.

Generating Notifications

Generating notifications is probably best done in a separate signal.

from django.db.models.signals import post_save
from notifications.signals import notify
from myapp.models import MyModel

def my_handler(sender, instance, created, **kwargs):
    notify.send(instance, verb='was saved')

post_save.connect(my_handler, sender=MyModel)

To generate an notification anywhere in your code, simply import the notify signal and send it with your actor, recipient, and verb.

from notifications.signals import notify

notify.send(user, recipient=user, verb='you reached level 10')

The complete syntax is.

notify.send(actor, recipient, verb, action_object, target, level, description, public, timestamp, **kwargs)

Arguments:

  • actor: An object of any type. (Required) Note: Use sender instead of actor if you intend to use keyword arguments
  • recipient: A Group or a User QuerySet or a list of User. (Required)
  • verb: An string. (Required)
  • action_object: An object of any type. (Optional)
  • target: An object of any type. (Optional)
  • level: One of Notification.LEVELS ('success', 'info', 'warning', 'error') (default=info). (Optional)
  • description: An string. (Optional)
  • public: An boolean (default=True). (Optional)
  • timestamp: An tzinfo (default=timezone.now()). (Optional)

Extra data

You can attach arbitrary data to your notifications by doing the following:

  • Add to your settings.py: DJANGO_NOTIFICATIONS_CONFIG = { 'USE_JSONFIELD': True}

Then, any extra arguments you pass to notify.send(...) will be attached to the .data attribute of the notification object. These will be serialised using the JSONField's serialiser, so you may need to take that into account: using only objects that will be serialised is a good idea.

Soft delete

By default, delete/(?P<slug>\d+)/ deletes specified notification record from DB. You can change this behaviour to "mark Notification.deleted field as True" by:

  • Add to your settings.py: DJANGO_NOTIFICATIONS_CONFIG = { 'SOFT_DELETE': True}

With this option, QuerySet methods unread and read contain one more filter: deleted=False. Meanwhile, QuerySet methods deleted, active, mark_all_as_deleted, mark_all_as_active are turned on. See more details in QuerySet methods section.

API

QuerySet methods

Using django-model-utils, we get the ability to add queryset methods to not only the manager, but to all querysets that will be used, including related objects. This enables us to do things like:

    Notification.objects.unread()

which returns all unread notifications. To do this for a single user, we can do:

    user = User.objects.get(pk=pk)
    user.notifications.unread()

There are some other QuerySet methods, too.

qs.unsent()

Return all of the unsent notifications, filtering the current queryset. (emailed=False)

qs.sent()

Return all of the sent notifications, filtering the current queryset. (emailed=True)

qs.unread()

Return all of the unread notifications, filtering the current queryset. When SOFT_DELETE=True, this filter contains deleted=False.

qs.read()

Return all of the read notifications, filtering the current queryset. When SOFT_DELETE=True, this filter contains deleted=False.

qs.mark_all_as_read() | qs.mark_all_as_read(recipient)

Mark all of the unread notifications in the queryset (optionally also filtered by recipient) as read.

qs.mark_all_as_unread() | qs.mark_all_as_unread(recipient)

Mark all of the read notifications in the queryset (optionally also filtered by recipient) as unread.

qs.mark_as_sent() | qs.mark_as_sent(recipient)

Mark all of the unsent notifications in the queryset (optionally also filtered by recipient) as sent.

qs.mark_as_unsent() | qs.mark_as_unsent(recipient)

Mark all of the sent notifications in the queryset (optionally also filtered by recipient) as unsent.

qs.deleted()

Return all notifications that have deleted=True, filtering the current queryset. Must be used with SOFT_DELETE=True.

qs.active()

Return all notifications that have deleted=False, filtering the current queryset. Must be used with DELETE=True.

qs.mark_all_as_deleted() | qs.mark_all_as_deleted(recipient)

Mark all notifications in the queryset (optionally also filtered by recipient) as deleted=True. Must be used with DELETE=True.

qs.mark_all_as_active() | qs.mark_all_as_active(recipient)

Mark all notifications in the queryset (optionally also filtered by recipient) as deleted=False. Must be used with SOFT_DELETE=True.

Model methods

obj.timesince([datetime])

A wrapper for Django's timesince function.

obj.mark_as_read()

Mark the current object as read.

Template tags

Put {% load notifications_tags %} in the template before you actually use notification tags.

notifications_unread

    {% notifications_unread %}

Give the number of unread notifications for a user, or nothing (an empty string) for an anonymous user.

Storing the count in a variable for further processing is advised, such as:

    {% notifications_unread as unread_count %}
    ...
    {% if unread_count %}
        You have <strong>{{ unread_count }}</strong> unread notifications.
    {% endif %}

Live-updater API

To ensure users always have the most up-to-date notifications, django-notifications includes a simple javascript API for updating specific fields within a django template.

There are two possible API calls that can be made:

  1. api/unread_count/ that returns a javascript object with 1 key: unread_count eg:

    {"unread_count":1}
    
  2. api/unread_list/ that returns a javascript object with 2 keys: unread_count and unread_list eg:

    {
     "unread_count":1,
     "unread_list":[--list of json representations of notifications--]
    }
    

    Representations of notifications are based on the django method: model_to_dict

    Query string arguments:

    • max - maximum length of unread list.
    • mark_as_read - mark notification in list as read.

    For example, get api/unread_list/?max=3&mark_as_read=true returns 3 notifications and mark them read (remove from list on next request).

    The list outputs target_url, actor_url, action_object_url. This URL is generated from standard Django Model.get_absolute_url() or you can override the URL just for notifications by implementing Model.get_url_for_notifications(notification, request).

How to use:

  1. Put {% load notifications_tags %} in the template before you actually use notification tags.

  2. In the area where you are loading javascript resources add the following tags in the order below:

    <script src="{% static 'notifications/notify.js' %}" type="text/javascript"></script>
    {% register_notify_callbacks callbacks='fill_notification_list,fill_notification_badge' %}
    

    register_notify_callbacks takes the following arguments:

    1. badge_class (default live_notify_badge) - The identifier class of the element to show the unread count, that will be periodically updated.
    2. menu_class (default live_notify_list) - The identifier class of the element to insert a list of unread items, that will be periodically updated.
    3. refresh_period (default 15) - How often to fetch unread items from the server (integer in seconds).
    4. fetch (default 5) - How many notifications to fetch each time.
    5. callbacks (default <empty string>) - A comma-separated list of javascript functions to call each period.
    6. api_name (default list) - The name of the API to call (this can be either list or count).
    7. mark_as_read (default False) - Marks notifications as read when fetched.
  3. To insert a live-updating unread count, use the following template:

    {% live_notify_badge %}
    

    live_notify_badge takes the following arguments:

    • badge_class (default live_notify_badge) - The identifier class for the <span> element that will be created to show the unread count.
  4. To insert a live-updating unread list, use the following template:

    {% live_notify_list %}
    

    live_notify_list takes the following arguments:

    • list_class (default live_notify_list) - The identifier class for the <ul> element that will be created to insert the list of notifications into.

Using the live-updater with bootstrap

The Live-updater can be incorporated into bootstrap with minimal code.

To create a live-updating bootstrap badge containing the unread count, simply use the template tag:

{% live_notify_badge badge_class="badge" %}

To create a live-updating bootstrap dropdown menu containing a selection of recent unread notifications, simply use the template tag:

{% live_notify_list list_class="dropdown-menu" %}

Customising the display of notifications using javascript callbacks

While the live notifier for unread counts should suit most use cases, users may wish to alter how unread notifications are shown.

The callbacks argument of the register_notify_callbacks dictates which javascript functions are called when the unread api call is made.

To add a custom javascript callback, simply add this to the list, like so:

{% register_notify_callbacks callbacks='fill_notification_badge,my_special_notification_callback' %}

The above would cause the callback to update the unread count badge, and would call the custom function my_special_notification_callback. All callback functions are passed a single argument by convention called data, which contains the entire result from the API.

For example, the below function would get the recent list of unread messages and log them to the console:

function my_special_notification_callback(data) {
    for (var i=0; i < data.unread_list.length; i++) {
        msg = data.unread_list[i];
        console.log(msg);
    }
}

Testing the live-updater

  1. Clone the repo
  2. Run ./manage.py runserver
  3. Browse to yourserverip/test/
  4. Click 'Make a notification' and a new notification should appear in the list in 5-10 seconds.

Serializing the django-notifications Model

See here - http://www.django-rest-framework.org/api-guide/relations/#generic-relationships

In this example the target object can be of type Foo or Bar and the appropriate serializer will be used.

class GenericNotificationRelatedField(serializers.RelatedField):

    def to_representation(self, value):
        if isinstance(value, Foo):
            serializer = FooSerializer(value)
        if isinstance(value, Bar):
            serializer = BarSerializer(value)

        return serializer.data


class NotificationSerializer(serializers.Serializer):
    recipient = PublicUserSerializer(User, read_only=True)
    unread = serializers.BooleanField(read_only=True)
    target = GenericNotificationRelatedField(read_only=True)

Thanks to @DaWy

AbstractNotification model

In case you need to customize the notification model in order to add field or customised features that depend on your application, you can inherit and extend the AbstractNotification model, example:

#In your_app/models.py

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

You will require to define NOTIFICATIONS_NOTIFICATION_MODEL setting in setting.py as follows:

# In your_project/settings.py

NOTIFICATIONS_NOTIFICATION_MODEL = 'your_app.Notification'

Notes

Email Notification

Sending email to users has not been integrated into this library. So for now you need to implement it if needed. There is a reserved field Notification.emailed to make it easier.

Sample App

A sample app has been implemented in notifications/tests/sample_notifications that extends django-notifications with the sole purpose of testing its extensibility. You can run the SAMPLE APP by setting the environment variable SAMPLE_APP as follows

export SAMPLE_APP=1
# Run the Django development server with sample_notifications app installed
python manage.py runserver
# Unset SAMPLE_APP to remove sample_notifications app from list of INSTALLED_APPS
unset SAMPLE_APP

django-notifications Team

Core contributors (in alphabetical order):

Contribute

We are looking for contributors, for anyone who'd like to contribute and willing to put time and energy on this project, please contact Yang Yubo.

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

django_notifications_pro-0.4.0.tar.gz (36.4 kB view details)

Uploaded Source

Built Distribution

django_notifications_pro-0.4.0-py2.py3-none-any.whl (43.6 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django_notifications_pro-0.4.0.tar.gz.

File metadata

File hashes

Hashes for django_notifications_pro-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9a40b668a159b1c9622b3926052bdc5fd68b1565f58ca237e1038648f7dca0f0
MD5 388d4f097b8165e30eefb0dfdfebdc44
BLAKE2b-256 727fe3c52b740a5ad021f459bc3cafba7c20baf1a737e29b05129a30d6e25a1d

See more details on using hashes here.

File details

Details for the file django_notifications_pro-0.4.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for django_notifications_pro-0.4.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 bfb26b3d2a60bef4e20409d30a5aeec23baeeb6ad9d665379274f3e515498d56
MD5 9e2ffc6eb75c61eaf738116a08662f77
BLAKE2b-256 e045db29abd6ee56bcbe14713c13d1cdc6e65477ca52e53a472267a77f28dca7

See more details on using hashes here.

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