diff --git a/README.rst b/README.rst index 22b5e4a..fbab7ea 100644 --- a/README.rst +++ b/README.rst @@ -123,7 +123,7 @@ Extra data You can attach arbitrary data to your notifications by doing the following: -* Add to your settings.py: ``NOTIFICATIONS_USE_JSONFIELD=True`` +* Add to your settings.py: ``DJANGO_NOTIFICATION_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. @@ -134,7 +134,7 @@ 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: ``NOTIFICATIONS_SOFT_DELETE=True`` +* Add to your settings.py: ``DJANGO_NOTIFICATION_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. @@ -171,13 +171,13 @@ Return all of the sent notifications, filtering the current queryset. (emailed=T ~~~~~~~~~~~~~~~ Return all of the unread notifications, filtering the current queryset. -When ``NOTIFICATIONS_SOFT_DELETE=True``, this filter contains ``deleted=False``. +When ``SOFT_DELETE=True``, this filter contains ``deleted=False``. ``qs.read()`` ~~~~~~~~~~~~~~~ Return all of the read notifications, filtering the current queryset. -When ``NOTIFICATIONS_SOFT_DELETE=True``, this filter contains ``deleted=False``. +When ``SOFT_DELETE=True``, this filter contains ``deleted=False``. ``qs.mark_all_as_read()`` | ``qs.mark_all_as_read(recipient)`` @@ -206,25 +206,25 @@ Mark all of the sent notifications in the queryset (optionally also filtered by ~~~~~~~~~~~~~~~~ Return all notifications that have ``deleted=True``, filtering the current queryset. -Must be used with ``NOTIFICATIONS_SOFT_DELETE=True``. +Must be used with ``SOFT_DELETE=True``. ``qs.active()`` ~~~~~~~~~~~~~~~ Return all notifications that have ``deleted=False``, filtering the current queryset. -Must be used with ``NOTIFICATIONS_SOFT_DELETE=True``. +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 ``NOTIFICATIONS_SOFT_DELETE=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 ``NOTIFICATIONS_SOFT_DELETE=True``. +Must be used with ``SOFT_DELETE=True``. Model methods diff --git a/notifications/models.py b/notifications/models.py index 7d49c50..54d485d 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -1,39 +1,34 @@ -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django import get_version -from django.utils import timezone - from distutils.version import StrictVersion +from django import get_version +from django.conf import settings +from django.contrib.auth.models import Group +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.db.models.query import QuerySet +from django.utils import timezone +from django.utils.six import text_type +from jsonfield.fields import JSONField +from model_utils import Choices +from notifications import settings as notifications_settings +from notifications.signals import notify + +from notifications.utils import id2slug + if StrictVersion(get_version()) >= StrictVersion('1.8.0'): from django.contrib.contenttypes.fields import GenericForeignKey else: from django.contrib.contenttypes.generic import GenericForeignKey -from django.db import models -from django.db.models.query import QuerySet -from django.core.exceptions import ImproperlyConfigured -from django.utils.six import text_type -from .utils import id2slug -from .signals import notify - -from model_utils import Choices -from jsonfield.fields import JSONField - -from django.contrib.auth.models import Group - - -# SOFT_DELETE = getattr(settings, 'NOTIFICATIONS_SOFT_DELETE', False) def is_soft_delete(): - # TODO: SOFT_DELETE = getattr(settings, ...) doesn't work with "override_settings" decorator in unittest - # But is_soft_delete is neither a very elegant way. Should try to find better approach - return getattr(settings, 'NOTIFICATIONS_SOFT_DELETE', False) + return notifications_settings.get_config()['SOFT_DELETE'] def assert_soft_delete(): if not is_soft_delete(): - msg = """To use 'deleted' field, please set 'NOTIFICATIONS_SOFT_DELETE'=True in settings. + msg = """To use 'deleted' field, please set 'SOFT_DELETE'=True in settings. Otherwise NotificationQuerySet.unread and NotificationQuerySet.read do NOT filter by 'deleted' field. """ raise ImproperlyConfigured(msg) @@ -242,9 +237,7 @@ class Notification(models.Model): self.unread = True self.save() -# 'NOTIFY_USE_JSONFIELD' is for backward compatibility -# As app name is 'notifications', let's use 'NOTIFICATIONS' consistently from now -EXTRA_DATA = getattr(settings, 'NOTIFY_USE_JSONFIELD', False) or getattr(settings, 'NOTIFICATIONS_USE_JSONFIELD', False) +EXTRA_DATA = notifications_settings.get_config()['USE_JSONFIELD'] def notify_handler(verb, **kwargs): diff --git a/notifications/settings.py b/notifications/settings.py new file mode 100644 index 0000000..9d30c55 --- /dev/null +++ b/notifications/settings.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from django.conf import settings + +CONFIG_DEFAULTS = { + 'PAGINATE_BY': 20, + 'JSONFIELD': False, + 'SOFT_DELETE': False +} + +def get_config(): + USER_CONFIG = getattr(settings, 'DJANGO_NOTIFICATION_CONFIG', {}) + + CONFIG = CONFIG_DEFAULTS.copy() + CONFIG.update(USER_CONFIG) + + return CONFIG diff --git a/notifications/tests/settings.py b/notifications/tests/settings.py index bd2ef31..4b1fe8c 100644 --- a/notifications/tests/settings.py +++ b/notifications/tests/settings.py @@ -54,7 +54,10 @@ TEMPLATES = [ }, ] -NOTIFICATIONS_USE_JSONFIELD = True LOGIN_REDIRECT_URL = 'test/' LOGIN_URL = '/admin/login/' APPEND_SLASH = True + +DJANGO_NOTIFICATION_CONFIG = { + 'USE_JSONFIELD': True, +} diff --git a/notifications/tests/tests.py b/notifications/tests/tests.py index f4851ea..a287cad 100644 --- a/notifications/tests/tests.py +++ b/notifications/tests/tests.py @@ -114,7 +114,9 @@ class NotificationManagersTest(TestCase): Notification.objects.filter(recipient=self.to_user).mark_all_as_read() self.assertEqual(self.to_user.notifications.unread().count(), 0) - @override_settings(NOTIFICATIONS_SOFT_DELETE=True) + @override_settings(DJANGO_NOTIFICATION_CONFIG={ + 'SOFT_DELETE': True + }) def test_mark_all_as_read_manager_with_soft_delete(self): # even soft-deleted notifications should be marked as read # refer: https://github.com/django-notifications/django-notifications/issues/126 @@ -138,7 +140,9 @@ class NotificationManagersTest(TestCase): self.assertRaises(ImproperlyConfigured, Notification.objects.mark_all_as_deleted) self.assertRaises(ImproperlyConfigured, Notification.objects.mark_all_as_active) - @override_settings(NOTIFICATIONS_SOFT_DELETE=True) + @override_settings(DJANGO_NOTIFICATION_CONFIG={ + 'SOFT_DELETE': True + }) def test_mark_all_deleted_manager(self): n = Notification.objects.filter(recipient=self.to_user).first() n.mark_as_read() @@ -246,7 +250,9 @@ class NotificationTestPages(TestCase): self.assertEqual(len(response.context['notifications']), len(self.to_user.notifications.unread())) self.assertEqual(len(response.context['notifications']), self.message_count-1) - @override_settings(NOTIFICATIONS_SOFT_DELETE=True) + @override_settings(DJANGO_NOTIFICATION_CONFIG={ + 'SOFT_DELETE': True + }) def test_soft_delete_messages_manager(self): self.login('to', 'pwd') diff --git a/notifications/views.py b/notifications/views.py index 249637f..115e60f 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -1,16 +1,15 @@ from distutils.version import StrictVersion from django import get_version -from django.conf import settings from django.contrib.auth.decorators import login_required from django.forms import model_to_dict from django.shortcuts import get_object_or_404, redirect from django.utils.decorators import method_decorator from django.views.generic import ListView -from .models import Notification -from .utils import id2slug, slug2id - +from notifications.models import Notification +from notifications.utils import id2slug, slug2id +from notifications import settings if StrictVersion(get_version()) >= StrictVersion('1.7.0'): from django.http import JsonResponse else: @@ -30,6 +29,7 @@ else: class NotificationViewList(ListView): template_name = 'notifications/list.html' context_object_name = 'notifications' + paginate_by = settings.get_config()['PAGINATE_BY'] @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): @@ -43,7 +43,7 @@ class AllNotificationsList(NotificationViewList): """ def get_queryset(self): - if getattr(settings, 'NOTIFICATIONS_SOFT_DELETE', False): + if settings.get_config()['SOFT_DELETE']: qs = self.request.user.notifications.active() else: qs = self.request.user.notifications.all() @@ -106,7 +106,7 @@ def delete(request, slug=None): notification = get_object_or_404( Notification, recipient=request.user, id=_id) - if getattr(settings, 'NOTIFICATIONS_SOFT_DELETE', False): + if settings.get_config()['SOFT_DELETE']: notification.deleted = True notification.save() else: