Package: django-notifications-test
django-notificationsDocumentationdjango-notificationsis a GitHub notification alike app for Django, it was derived fromdjango-activity-streamThe major difference betweendjango-notificationsanddjango-activity-stream:django-notificationsis for building something like Github "Notifications"Whiledjango-activity-streamis 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 ObjectandTargetareGenericForeignKeysto any
arbitrary Django object. An action is a description of an action that
was performed (Verb) at some instant in time by someActoron some
optionalTargetthat results in anAction Objectgetting
created/updated/deleted.For example:justquick(actor)closed(verb)issue
2(action_object)onactivity-stream(target)12 hours agoNomenclature of this specification is based on the Activity Streams
Spec:http://activitystrea.ms/specs/atom/1.0/RequirementsPython 3.7, 3.8, 3.9, 3.10, 3.11Django 3.2, 4.0, 4.1InstallationInstallation is easy usingpipand will install all required
libraries.$pipinstalldjango-notifications-hqor get it from source$gitclonehttps://github.com/django-notifications/django-notifications
$cddjango-notifications
$pythonsetup.pysdist
$pipinstalldist/django-notifications-hq*Note thatdjango-model-utilswill be installed: this is required for the pass-through QuerySet manager.Then to add the Django Notifications to your project add the appnotificationsto yourINSTALLED_APPSand urlconf.The app should go somewhere after all the apps that are going to be
generating notifications likedjango.contrib.authINSTALLED_APPS=('django.contrib.auth',...'notifications',...)Add the notifications urls to your urlconf:importnotifications.urlsurlpatterns=[...url('^inbox/notifications/',include(notifications.urls,namespace='notifications')),...]The method of installing these urls, importing rather than using'notifications.urls', is required to ensure that the urls are
installed in thenotificationsnamespace.To run schema migration, executepython manage.py migrate notifications.Generating NotificationsGenerating notifications is probably best done in a separate signal.fromdjango.db.models.signalsimportpost_savefromnotifications.signalsimportnotifyfrommyapp.modelsimportMyModeldefmy_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.fromnotifications.signalsimportnotifynotify.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: Usesenderinstead ofactorif you intend to use keyword
argumentsrecipient: AGroupor aUser QuerySetor a list ofUser. (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 dataYou 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 tonotify.send(...)will be
attached to the.dataattribute 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 deleteBy default,delete/(?P<slug>\d+)/deletes specified notification
record from DB. You can change this behaviour to "markNotification.deletedfield asTrue" by:Add to your settings.py:DJANGO_NOTIFICATIONS_CONFIG = { 'SOFT_DELETE': True}With this option, QuerySet methodsunreadandreadcontain one more
filter:deleted=False. Meanwhile, QuerySet methodsdeleted,active,mark_all_as_deleted,mark_all_as_activeare turned on. See
more details in QuerySet methods section.APIQuerySet methodsUsingdjango-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.
WhenSOFT_DELETE=True, this filter containsdeleted=False.qs.read()Return all of the read notifications, filtering the current queryset.
WhenSOFT_DELETE=True, this filter containsdeleted=False.qs.mark_all_as_read()|qs.mark_all_as_read(recipient)Mark all of the unread notifications in the queryset (optionally also
filtered byrecipient) 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 byrecipient) as unread.qs.mark_as_sent()|qs.mark_as_sent(recipient)Mark all of the unsent notifications in the queryset (optionally also
filtered byrecipient) as sent.qs.mark_as_unsent()|qs.mark_as_unsent(recipient)Mark all of the sent notifications in the queryset (optionally also
filtered byrecipient) as unsent.qs.deleted()Return all notifications that havedeleted=True, filtering the current
queryset. Must be used withSOFT_DELETE=True.qs.active()Return all notifications that havedeleted=False, filtering the
current queryset. Must be used withDELETE=True.qs.mark_all_as_deleted()|qs.mark_all_as_deleted(recipient)Mark all notifications in the queryset (optionally also filtered byrecipient) asdeleted=True. Must be used withDELETE=True.qs.mark_all_as_active()|qs.mark_all_as_active(recipient)Mark all notifications in the queryset (optionally also filtered byrecipient) asdeleted=False. Must be used withSOFT_DELETE=True.Model methodsobj.timesince([datetime])A wrapper for Django'stimesincefunction.obj.mark_as_read()Mark the current object as read.Template tagsPut{% 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_unreadasunread_count%}...{%ifunread_count%}Youhave<strong>{{unread_count}}</strong>unreadnotifications.{%endif%}Live-updater APITo ensure users always have the most up-to-date notifications,django-notificationsincludes a simple javascript API for
updating specific fields within a django template.There are two possible API calls that can be made:api/unread_count/that returns a javascript object with 1 key:unread_counteg:{"unread_count":1}api/unread_list/that returns a javascript object with 2 keys:unread_countandunread_listeg:{
 "unread_count":1,
 "unread_list":[--list of json representations of notifications--]
}Representations of notifications are based on the django method:model_to_dictQuery string arguments:max- maximum length of unread list.mark_as_read- mark notification in list as read.For example, getapi/unread_list/?max=3&mark_as_read=truereturns
3 notifications and mark them read (remove from list on next
request).How to use:Put{% load notifications_tags %}in the template before you
actually use notification tags.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_callbackstakes the following arguments:badge_class(defaultlive_notify_badge) - The identifierclassof the element to show the unread count,
that will be periodically updated.menu_class(defaultlive_notify_list) - The identifierclassof the element to insert a list of unread
items, that will be periodically updated.refresh_period(default15) - How often to fetch unread
items from the server (integer in seconds).fetch(default5) - How many notifications to fetch each
time.callbacks(default<empty string>) - A comma-separated list
of javascript functions to call each period.api_name(defaultlist) - The name of the API to call (this
can be eitherlistorcount).To insert a live-updating unread count, use the following template:{% live_notify_badge %}live_notify_badgetakes the following arguments:badge_class(defaultlive_notify_badge) - The identifierclassfor the<span>element that will be created to show
the unread count.To insert a live-updating unread list, use the following template:{% live_notify_list %}live_notify_listtakes the following arguments:list_class(defaultlive_notify_list) - The identifierclassfor the<ul>element that will be created to insert
the list of notifications into.Using the live-updater with bootstrapThe 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 callbacksWhile the live notifier for unread counts should suit most use cases,
users may wish to alter how unread notifications are shown.Thecallbacksargument of theregister_notify_callbacksdictates
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 functionmy_special_notification_callback. All callback
functions are passed a single argument by convention calleddata, 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:functionmy_special_notification_callback(data){for(vari=0;i<data.unread_list.length;i++){msg=data.unread_list[i];console.log(msg);}}Testing the live-updaterClone the repoRun./manage.py runserverBrowse toyourserverip/test/Click 'Make a notification' and a new notification should appear
in the list in 5-10 seconds.Serializing the django-notifications ModelSee here -http://www.django-rest-framework.org/api-guide/relations/#generic-relationshipsIn this example the target object can be of type Foo or Bar and the
appropriate serializer will be used.classGenericNotificationRelatedField(serializers.RelatedField):defto_representation(self,value):ifisinstance(value,Foo):serializer=FooSerializer(value)ifisinstance(value,Bar):serializer=BarSerializer(value)returnserializer.dataclassNotificationSerializer(serializers.Serializer):recipient=PublicUserSerializer(User,read_only=True)unread=serializers.BooleanField(read_only=True)target=GenericNotificationRelatedField(read_only=True)Thanks to @DaWyAbstractNotificationmodelIn 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 theAbstractNotificationmodel, example:#In your_app/models.pyfromdjango.dbimportmodelsfromnotifications.base.modelsimportAbstractNotificationclassNotification(AbstractNotification):# custom field examplecategory=models.ForeignKey('myapp.Category',on_delete=models.CASCADE)classMeta(AbstractNotification.Meta):abstract=FalseYou will require to defineNOTIFICATIONS_NOTIFICATION_MODELsetting insetting.pyas follows:# In your_project/settings.pyNOTIFICATIONS_NOTIFICATION_MODEL='your_app.Notification'NotesEmail NotificationSending email to users has not been integrated into this library. So for
now you need to implement it if needed. There is a reserved fieldNotification.emailedto make it easier.Sample AppA sample app has been implemented innotifications/tests/sample_notificationsthat extendsdjango-notificationswith the sole purpose of testing its
extensibility. You can run the SAMPLE APP by setting the environment
variableSAMPLE_APPas followsexportSAMPLE_APP=1# Run the Django development server with sample_notifications app installedpythonmanage.pyrunserver# Unset SAMPLE_APP to remove sample_notifications app from list of INSTALLED_APPSunsetSAMPLE_APPdjango-notificationsTeamCore contributors (in alphabetical order):Alvaro LeonelFederico CapoanoSamuel SpencerYang YuboYPCrumbleZhongyuan ZhangContributeWe are looking for contributors, for anyone who'd like to contribute
and willing to put time and energy on this project, please contactYang
Yubo.