From cc04ef119f17cf8bfb5db00bed899acd99cc5d6c Mon Sep 17 00:00:00 2001 From: "Yang.Y" Date: Thu, 17 Nov 2022 18:05:22 +0800 Subject: [PATCH] Convert README to markdown --- README.md | 518 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 481 ------------------------------------------------- 2 files changed, 518 insertions(+), 481 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 0000000..8fa5b54 --- /dev/null +++ b/README.md @@ -0,0 +1,518 @@ +# `django-notifications` Documentation + +[![build-status](https://travis-ci.org/django-notifications/django-notifications.svg)](https://travis-ci.org/django-notifications/django-notifications) +[![Coverage Status](https://coveralls.io/repos/github/django-notifications/django-notifications/badge.svg?branch=master)](https://coveralls.io/github/django-notifications/django-notifications?branch=master) + + +[django-notifications](https://github.com/django-notifications/django-notifications) is a GitHub notification alike app for Django, it was derived from [django-activity-stream](https://github.com/justquick/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](https://github.com/justquick/) `(actor)` +*closed* `(verb)` [issue +2](https://github.com/justquick/django-activity-stream/issues/2) +`(action_object)` on +[activity-stream](https://github.com/justquick/django-activity-stream/) +`(target)` 12 hours ago + +Nomenclature of this specification is based on the Activity Streams +Spec: + +## 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. +```bash +$ pip install django-notifications-hq +``` +or get it from source + +```bash +$ 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](http://pypi.python.org/pypi/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` + +```python +INSTALLED_APPS = ( + 'django.contrib.auth', + ... + 'notifications', + ... +) +``` + +Add the notifications urls to your urlconf: + +```python +import notifications.urls + +urlpatterns = [ + ... + 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 the `notifications` namespace. + +To run schema migration, execute +`python manage.py migrate notifications`. + +## Generating Notifications + +Generating notifications is probably best done in a separate signal. + +```python +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. + +```python +from notifications.signals import notify + +notify.send(user, recipient=user, verb='you reached level 10') +``` + +The complete syntax is. + +```python +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\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: + +```python + Notification.objects.unread() +``` + +which returns all unread notifications. To do this for a single user, we +can do: + +```python + 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` + +```python + {% 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: + +```python + {% notifications_unread as unread_count %} + ... + {% if unread_count %} + You have {{ unread_count }} 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). + +### 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: + + + {% 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 ``) - 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`). + +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 `` 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 `
    ` 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: + +```javascript +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 - + +In this example the target object can be of type Foo or Bar and the +appropriate serializer will be used. + +```python +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: + +```python +#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: + +```python +# 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 + +```bash +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): + +- [Alvaro Leonel](https://github.com/AlvaroLQueiroz) +- [Federico Capoano](https://github.com/nemesisdesign) +- [Samuel Spencer](https://github.com/LegoStormtroopr) +- [Yang Yubo](https://github.com/yangyubo) +- [YPCrumble](https://github.com/YPCrumble) +- [Zhongyuan Zhang](https://github.com/zhang-z) + +## 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](https://github.com/yangyubo). diff --git a/README.rst b/README.rst deleted file mode 100644 index 5520ccb..0000000 --- a/README.rst +++ /dev/null @@ -1,481 +0,0 @@ -``django-notifications`` Documentation -======================================= - - -|build-status| |coveralls| - -`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: ``_ - -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:: - - import notifications.urls - - urlpatterns = [ - ... - 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 the ``notifications`` namespace. - -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\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 {{ unread_count }} 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} - -#. ``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). - - -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:: - - - {% 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. - #. ``menu_class`` (default ``live_notify_list``) - The identifier `class` of the element to insert a list of unread items, that will be periodically updated. - #. ``refresh_period`` (default ``15``) - How often to fetch unread items from the server (integer in seconds). - #. ``fetch`` (default ``5``) - How many notifications to fetch each time. - #. ``callbacks`` (default ````) - A comma-separated list of javascript functions to call each period. - #. ``api_name`` (default ``list``) - The name of the API to call (this can be either ``list`` or ``count``). - -3. To insert a live-updating unread count, use the following template:: - - {% live_notify_badge %} - - ``live_notify_badge`` takes the following arguments: - - 1. ``badge_class`` (default ``live_notify_badge``) - The identifier ``class`` for the ```` 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: - - 1. ``list_class`` (default ``live_notify_list``) - The identifier ``class`` for the ``
      `` 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: - -.. code-block:: python - - #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: - -.. code-block:: python - - # 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 - -.. code-block:: shell - - 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): - -- `Alvaro Leonel `_ -- `Federico Capoano `_ -- `Samuel Spencer `_ -- `Yang Yubo `_ -- `YPCrumble` `_ -- `Zhongyuan Zhang `_ - -.. |build-status| image:: https://travis-ci.org/django-notifications/django-notifications.svg - :target: https://travis-ci.org/django-notifications/django-notifications - -.. |coveralls| image:: https://coveralls.io/repos/django-notifications/django-notifications/badge.png?branch=master - :alt: Code coverage on coveralls - :scale: 100% - :target: https://coveralls.io/r/django-notifications/django-notifications?branch=master - -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 `_.