GitHub notifications alike app for Django providing comprehensive activity tracking and notification features.
—
Helper functions for formatting notifications, converting IDs to URL-safe slugs, and retrieving notification data for API responses with configurable limits and pagination.
Functions for processing and formatting notification data for API responses and template display.
def get_notification_list(request, method_name='all'):
"""
Get formatted notification list for API responses.
Args:
request: Django HTTP request object
method_name (str): QuerySet method name ('all', 'unread', 'read', etc.)
Query Parameters (from request.GET):
max (int): Maximum notifications to return (1-100)
mark_as_read (str): Mark notifications as read if parameter exists
Returns:
list: List of notification dictionaries with formatted data
Dictionary structure:
{
'id': int,
'slug': int,
'actor': str,
'verb': str,
'target': str or None,
'action_object': str or None,
'description': str,
'timestamp': datetime,
'unread': bool,
'level': str,
'public': bool,
'deleted': bool,
'emailed': bool,
'data': dict
}
"""
def get_num_to_fetch(request):
"""
Extract and validate number of notifications to fetch from request.
Args:
request: Django HTTP request object
Query Parameters (from request.GET):
max (int, optional): Number of notifications requested
Returns:
int: Validated number between 1-100, defaults to NUM_TO_FETCH setting
Validation:
- Must be integer
- Must be between 1 and 100 inclusive
- Falls back to default if invalid
"""Utility functions for converting between notification IDs and URL-safe slugs for secure URL patterns.
def slug2id(slug):
"""
Convert notification slug back to database ID.
Args:
slug (int or str): URL slug representing notification
Returns:
int: Database ID for notification lookup
Formula: ID = slug - 110909
"""
def id2slug(notification_id):
"""
Convert notification database ID to URL-safe slug.
Args:
notification_id (int): Database ID of notification
Returns:
int: URL-safe slug for use in URLs and templates
Formula: slug = ID + 110909
"""from notifications.helpers import get_notification_list, get_num_to_fetch
from django.http import JsonResponse
def custom_notification_api(request):
"""Custom API endpoint using helper functions."""
# Get validated number to fetch
num_to_fetch = get_num_to_fetch(request)
print(f"Fetching {num_to_fetch} notifications")
# Get formatted notification list
unread_notifications = get_notification_list(request, 'unread')
all_notifications = get_notification_list(request, 'all')
return JsonResponse({
'unread': unread_notifications,
'all': all_notifications,
'meta': {
'requested_count': num_to_fetch,
'unread_count': len(unread_notifications),
'all_count': len(all_notifications)
}
})
# Example request: /api/notifications/?max=25&mark_as_read=true
# Returns formatted notification data with auto-read functionalityfrom django.shortcuts import render
from django.contrib.auth.decorators import login_required
from notifications.helpers import get_notification_list
@login_required
def dashboard_notifications(request):
"""Dashboard view showing formatted notifications."""
# Get recent notifications for display
recent_notifications = get_notification_list(request, 'all')[:5]
unread_notifications = get_notification_list(request, 'unread')
# Process notifications for template
processed_notifications = []
for notification in recent_notifications:
processed_notifications.append({
'id': notification['id'],
'display_text': f"{notification['actor']} {notification['verb']}",
'target_text': notification.get('target', ''),
'time_ago': notification['timestamp'],
'is_unread': notification['unread'],
'edit_url': f"/admin/notifications/notification/{notification['id']}/change/",
'mark_read_url': f"/notifications/mark-as-read/{notification['slug']}/"
})
return render(request, 'dashboard/notifications.html', {
'notifications': processed_notifications,
'unread_count': len(unread_notifications)
})from notifications.utils import id2slug, slug2id
from notifications.models import Notification
# Convert ID to slug for URL
notification = Notification.objects.get(id=123)
url_slug = id2slug(notification.id)
print(f"URL slug: {url_slug}") # Output: 111032
# Use in URL pattern
notification_url = f"/notifications/mark-as-read/{url_slug}/"
# Convert slug back to ID for database lookup
def mark_notification_read(request, slug):
notification_id = slug2id(slug)
notification = Notification.objects.get(
id=notification_id,
recipient=request.user
)
notification.mark_as_read()
return redirect('notifications:all')
# Bulk slug operations
notification_ids = [100, 101, 102, 103]
slugs = [id2slug(nid) for nid in notification_ids]
print(f"Slugs: {slugs}") # [111009, 111010, 111011, 111012]
# Convert back
original_ids = [slug2id(slug) for slug in slugs]
print(f"Original IDs: {original_ids}") # [100, 101, 102, 103]from notifications.helpers import get_num_to_fetch
def process_notification_request(request):
"""Demonstrate request parameter processing."""
# Various request scenarios
test_requests = [
{'GET': {}}, # Default: 10
{'GET': {'max': '25'}}, # Valid: 25
{'GET': {'max': '150'}}, # Too large: 10 (default)
{'GET': {'max': '0'}}, # Too small: 10 (default)
{'GET': {'max': 'invalid'}}, # Invalid: 10 (default)
{'GET': {'max': '50'}}, # Valid: 50
]
results = []
for req_data in test_requests:
# Mock request object
class MockRequest:
def __init__(self, get_data):
self.GET = get_data
mock_request = MockRequest(req_data['GET'])
num_to_fetch = get_num_to_fetch(mock_request)
results.append({
'input': req_data['GET'].get('max', 'not provided'),
'output': num_to_fetch
})
return results
# Example output:
# [
# {'input': 'not provided', 'output': 10},
# {'input': '25', 'output': 25},
# {'input': '150', 'output': 10},
# {'input': '0', 'output': 10},
# {'input': 'invalid', 'output': 10},
# {'input': '50', 'output': 50}
# ]from notifications.helpers import get_notification_list
from django.contrib.humanize.templatetags.humanize import naturaltime
def format_notifications_for_email(user, max_notifications=20):
"""Format notifications for email digest."""
# Create mock request for helper function
class MockRequest:
def __init__(self, user, max_count):
self.user = user
self.GET = {'max': str(max_count)}
mock_request = MockRequest(user, max_notifications)
notifications = get_notification_list(mock_request, 'unread')
formatted_notifications = []
for notification in notifications:
formatted_notifications.append({
'subject': f"New notification: {notification['verb']}",
'message': notification.get('description',
f"{notification['actor']} {notification['verb']}"),
'time': naturaltime(notification['timestamp']),
'actor': notification['actor'],
'action': notification['verb'],
'target': notification.get('target'),
'url': f"https://example.com/notifications/mark-as-read/{notification['slug']}/"
})
return formatted_notifications
# Usage
user_notifications = format_notifications_for_email(user, 10)
for notif in user_notifications:
print(f"Email: {notif['subject']}")
print(f"Content: {notif['message']}")
print(f"Time: {notif['time']}")
print("---")from notifications.helpers import get_num_to_fetch
from django.core.paginator import Paginator
def paginated_notifications(request, method_name='all'):
"""Get paginated notifications using helper functions."""
# Get number to fetch per page
per_page = get_num_to_fetch(request)
# Get user's notifications
if method_name == 'unread':
notifications = request.user.notifications.unread()
elif method_name == 'read':
notifications = request.user.notifications.read()
else:
notifications = request.user.notifications.all()
# Create paginator
paginator = Paginator(notifications, per_page)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
# Format notifications for response
formatted_notifications = []
for notification in page_obj:
formatted_notifications.append({
'id': notification.id,
'slug': notification.slug,
'actor': str(notification.actor),
'verb': notification.verb,
'target': str(notification.target) if notification.target else None,
'description': notification.description,
'timestamp': notification.timestamp,
'unread': notification.unread,
'level': notification.level
})
return {
'notifications': formatted_notifications,
'pagination': {
'has_previous': page_obj.has_previous(),
'has_next': page_obj.has_next(),
'previous_page_number': page_obj.previous_page_number() if page_obj.has_previous() else None,
'next_page_number': page_obj.next_page_number() if page_obj.has_next() else None,
'current_page': page_obj.number,
'total_pages': page_obj.paginator.num_pages,
'total_count': page_obj.paginator.count,
'per_page': per_page
}
}
# Usage in view
def notification_list_api(request):
result = paginated_notifications(request, 'unread')
return JsonResponse(result)from notifications.utils import slug2id
from notifications.models import Notification
def bulk_mark_notifications_read(request):
"""Mark multiple notifications as read using slugs."""
# Get slugs from request (e.g., form data or JSON)
slugs = request.POST.getlist('notification_slugs')
# or from JSON: slugs = json.loads(request.body).get('slugs', [])
# Convert slugs to IDs
notification_ids = [slug2id(slug) for slug in slugs]
# Bulk update notifications
updated_count = Notification.objects.filter(
id__in=notification_ids,
recipient=request.user,
unread=True
).update(unread=False)
return JsonResponse({
'success': True,
'updated_count': updated_count,
'processed_ids': notification_ids
})
def generate_notification_urls(notifications):
"""Generate URLs for a list of notifications."""
urls = {}
for notification in notifications:
slug = notification.slug # Uses property from model
urls[notification.id] = {
'mark_read': f"/notifications/mark-as-read/{slug}/",
'mark_unread': f"/notifications/mark-as-unread/{slug}/",
'delete': f"/notifications/delete/{slug}/",
'detail': f"/notifications/{slug}/"
}
return urls
# Example usage
user_notifications = user.notifications.unread()[:10]
notification_urls = generate_notification_urls(user_notifications)
for notification in user_notifications:
urls = notification_urls[notification.id]
print(f"Notification {notification.id}:")
print(f" Mark Read: {urls['mark_read']}")
print(f" Delete: {urls['delete']}")Install with Tessl CLI
npx tessl i tessl/pypi-django-notifications-hq