GitHub notifications alike app for Django providing comprehensive activity tracking and notification features.
—
Configurable settings for pagination, soft deletion, JSON field usage, caching, and other behavioral options with sensible defaults and Django settings integration.
Function to retrieve merged configuration combining defaults with user-specified settings.
def get_config():
"""
Get merged configuration with user settings and defaults.
Returns:
dict: Configuration dictionary with all settings
Configuration Keys:
PAGINATE_BY (int): Number of notifications per page (default: 20)
USE_JSONFIELD (bool): Enable JSONField for extra data (default: False)
SOFT_DELETE (bool): Use soft deletion instead of hard delete (default: False)
NUM_TO_FETCH (int): Default number for API endpoints (default: 10)
CACHE_TIMEOUT (int): Cache timeout in seconds (default: 2)
Django Setting:
DJANGO_NOTIFICATIONS_CONFIG (dict): User configuration overrides
"""CONFIG_DEFAULTS = {
'PAGINATE_BY': 20,
'USE_JSONFIELD': False,
'SOFT_DELETE': False,
'NUM_TO_FETCH': 10,
'CACHE_TIMEOUT': 2,
}# In your Django settings.py
DJANGO_NOTIFICATIONS_CONFIG = {
'PAGINATE_BY': 25, # Show 25 notifications per page
'USE_JSONFIELD': True, # Enable extra data storage
'SOFT_DELETE': True, # Use soft deletion
'NUM_TO_FETCH': 15, # Fetch 15 notifications by default in API
'CACHE_TIMEOUT': 30, # Cache notification counts for 30 seconds
}
# The configuration is automatically loaded by the package
from notifications.settings import get_config
config = get_config()
print(config['PAGINATE_BY']) # Output: 25
print(config['SOFT_DELETE']) # Output: True# settings/production.py
DJANGO_NOTIFICATIONS_CONFIG = {
# Higher pagination for performance
'PAGINATE_BY': 50,
# Enable JSON field for rich notification data
'USE_JSONFIELD': True,
# Use soft delete to maintain data integrity
'SOFT_DELETE': True,
# Fetch more notifications for mobile apps
'NUM_TO_FETCH': 25,
# Longer cache timeout for better performance
'CACHE_TIMEOUT': 300, # 5 minutes
}# settings/development.py
DJANGO_NOTIFICATIONS_CONFIG = {
# Smaller pagination for easier testing
'PAGINATE_BY': 5,
# Enable JSON field for testing data structures
'USE_JSONFIELD': True,
# Disable soft delete for easier debugging
'SOFT_DELETE': False,
# Fetch fewer notifications for faster development
'NUM_TO_FETCH': 5,
# Short cache timeout for immediate feedback
'CACHE_TIMEOUT': 1,
}from notifications.settings import get_config
def create_notification_page(request):
"""Create paginated notification view using configuration."""
config = get_config()
notifications = request.user.notifications.all()
# Use configured pagination
paginator = Paginator(notifications, config['PAGINATE_BY'])
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'notifications/list.html', {
'notifications': page_obj,
'config': config
})
def send_rich_notification(sender, recipient, verb, **extra_data):
"""Send notification with optional JSON data based on configuration."""
config = get_config()
notification_kwargs = {
'sender': sender,
'recipient': recipient,
'verb': verb
}
# Only include extra data if JSON field is enabled
if config['USE_JSONFIELD'] and extra_data:
notification_kwargs.update(extra_data)
notify.send(**notification_kwargs)
def get_cached_notification_count(user):
"""Get notification count with configured cache timeout."""
config = get_config()
cache_key = f'notification_count_{user.id}'
count = cache.get(cache_key)
if count is None:
count = user.notifications.unread().count()
cache.set(cache_key, count, config['CACHE_TIMEOUT'])
return countfrom notifications.settings import get_config
class NotificationManager:
def __init__(self):
self.config = get_config()
def delete_notification(self, notification):
"""Delete notification using configured deletion method."""
if self.config['SOFT_DELETE']:
notification.deleted = True
notification.save()
else:
notification.delete()
def get_active_notifications(self, user):
"""Get notifications respecting soft delete configuration."""
notifications = user.notifications.all()
if self.config['SOFT_DELETE']:
notifications = notifications.filter(deleted=False)
return notifications
def prepare_notification_data(self, notification, extra_data=None):
"""Prepare notification data based on configuration."""
data = {
'actor': str(notification.actor),
'verb': notification.verb,
'timestamp': notification.timestamp.isoformat(),
}
# Include JSON data if enabled
if self.config['USE_JSONFIELD'] and notification.data:
data['extra_data'] = notification.data
# Include additional data if provided and JSON field enabled
if self.config['USE_JSONFIELD'] and extra_data:
data.update(extra_data)
return data
# Usage
manager = NotificationManager()
user_notifications = manager.get_active_notifications(user)from notifications.settings import get_config
from django.http import JsonResponse
def notification_api_endpoint(request):
"""API endpoint that respects configuration settings."""
config = get_config()
# Use configured default fetch count
max_count = request.GET.get('max', config['NUM_TO_FETCH'])
try:
max_count = min(int(max_count), 100) # Cap at 100
except (ValueError, TypeError):
max_count = config['NUM_TO_FETCH']
notifications = request.user.notifications.unread()[:max_count]
notification_list = []
for notification in notifications:
notif_data = {
'id': notification.id,
'actor': str(notification.actor),
'verb': notification.verb,
'timestamp': notification.timestamp.isoformat(),
}
# Include JSON data if configured
if config['USE_JSONFIELD'] and notification.data:
notif_data['data'] = notification.data
notification_list.append(notif_data)
return JsonResponse({
'notifications': notification_list,
'count': len(notification_list),
'config': {
'max_per_request': config['NUM_TO_FETCH'],
'pagination_size': config['PAGINATE_BY'],
'cache_timeout': config['CACHE_TIMEOUT']
}
})from notifications.settings import get_config
def add_config_to_context(request):
"""Context processor to add configuration to templates."""
return {
'notifications_config': get_config()
}
# In settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'context_processors': [
# ... other context processors
'myapp.context_processors.add_config_to_context',
],
},
},
]<!-- In templates -->
{% load notifications_tags %}
<!-- Use configuration in templates -->
<div class="notifications-config">
<p>Showing {{ notifications_config.PAGINATE_BY }} notifications per page</p>
{% if notifications_config.SOFT_DELETE %}
<p>Deleted notifications are preserved</p>
{% endif %}
{% if notifications_config.USE_JSONFIELD %}
<!-- Show rich notification data -->
{% for notification in notifications %}
{% if notification.data %}
<div class="notification-extra-data">
{{ notification.data|safe }}
</div>
{% endif %}
{% endfor %}
{% endif %}
</div>
<!-- Configure template tag with settings -->
{% register_notify_callbacks
fetch=notifications_config.NUM_TO_FETCH
refresh_period=notifications_config.CACHE_TIMEOUT
%}# Custom management command to handle configuration changes
from django.core.management.base import BaseCommand
from notifications.settings import get_config
from notifications.models import Notification
class Command(BaseCommand):
help = 'Migrate notifications based on configuration changes'
def handle(self, *args, **options):
config = get_config()
if config['SOFT_DELETE']:
# Ensure deleted field exists and is properly indexed
self.stdout.write("Soft delete is enabled")
# Count notifications that would be affected
hard_deleted_count = Notification.objects.filter(deleted=True).count()
self.stdout.write(f"Found {hard_deleted_count} soft-deleted notifications")
else:
# Warn about data that might be lost
soft_deleted_count = Notification.objects.filter(deleted=True).count()
if soft_deleted_count > 0:
self.stdout.write(
self.style.WARNING(
f"Warning: {soft_deleted_count} soft-deleted notifications exist "
"but SOFT_DELETE is False. These may not be visible."
)
)
if config['USE_JSONFIELD']:
# Check for notifications with JSON data
with_data_count = Notification.objects.exclude(data__isnull=True).count()
self.stdout.write(f"Found {with_data_count} notifications with JSON data")
self.stdout.write(
self.style.SUCCESS(f"Configuration check complete. Current settings: {config}")
)# settings/base.py
import os
# Base notification configuration
DJANGO_NOTIFICATIONS_CONFIG = {
'PAGINATE_BY': int(os.environ.get('NOTIFICATIONS_PAGINATE_BY', '20')),
'USE_JSONFIELD': os.environ.get('NOTIFICATIONS_USE_JSONFIELD', 'False').lower() == 'true',
'SOFT_DELETE': os.environ.get('NOTIFICATIONS_SOFT_DELETE', 'False').lower() == 'true',
'NUM_TO_FETCH': int(os.environ.get('NOTIFICATIONS_NUM_TO_FETCH', '10')),
'CACHE_TIMEOUT': int(os.environ.get('NOTIFICATIONS_CACHE_TIMEOUT', '2')),
}
# Environment variables:
# NOTIFICATIONS_PAGINATE_BY=25
# NOTIFICATIONS_USE_JSONFIELD=true
# NOTIFICATIONS_SOFT_DELETE=true
# NOTIFICATIONS_NUM_TO_FETCH=15
# NOTIFICATIONS_CACHE_TIMEOUT=30Install with Tessl CLI
npx tessl i tessl/pypi-django-notifications-hq