0
# Utilities
1
2
Helper functions for formatting notifications, converting IDs to URL-safe slugs, and retrieving notification data for API responses with configurable limits and pagination.
3
4
## Capabilities
5
6
### Notification Helper Functions
7
8
Functions for processing and formatting notification data for API responses and template display.
9
10
```python { .api }
11
def get_notification_list(request, method_name='all'):
12
"""
13
Get formatted notification list for API responses.
14
15
Args:
16
request: Django HTTP request object
17
method_name (str): QuerySet method name ('all', 'unread', 'read', etc.)
18
19
Query Parameters (from request.GET):
20
max (int): Maximum notifications to return (1-100)
21
mark_as_read (str): Mark notifications as read if parameter exists
22
23
Returns:
24
list: List of notification dictionaries with formatted data
25
26
Dictionary structure:
27
{
28
'id': int,
29
'slug': int,
30
'actor': str,
31
'verb': str,
32
'target': str or None,
33
'action_object': str or None,
34
'description': str,
35
'timestamp': datetime,
36
'unread': bool,
37
'level': str,
38
'public': bool,
39
'deleted': bool,
40
'emailed': bool,
41
'data': dict
42
}
43
"""
44
45
def get_num_to_fetch(request):
46
"""
47
Extract and validate number of notifications to fetch from request.
48
49
Args:
50
request: Django HTTP request object
51
52
Query Parameters (from request.GET):
53
max (int, optional): Number of notifications requested
54
55
Returns:
56
int: Validated number between 1-100, defaults to NUM_TO_FETCH setting
57
58
Validation:
59
- Must be integer
60
- Must be between 1 and 100 inclusive
61
- Falls back to default if invalid
62
"""
63
```
64
65
### ID and Slug Conversion
66
67
Utility functions for converting between notification IDs and URL-safe slugs for secure URL patterns.
68
69
```python { .api }
70
def slug2id(slug):
71
"""
72
Convert notification slug back to database ID.
73
74
Args:
75
slug (int or str): URL slug representing notification
76
77
Returns:
78
int: Database ID for notification lookup
79
80
Formula: ID = slug - 110909
81
"""
82
83
def id2slug(notification_id):
84
"""
85
Convert notification database ID to URL-safe slug.
86
87
Args:
88
notification_id (int): Database ID of notification
89
90
Returns:
91
int: URL-safe slug for use in URLs and templates
92
93
Formula: slug = ID + 110909
94
"""
95
```
96
97
### Usage Examples
98
99
#### API Response Formatting
100
101
```python
102
from notifications.helpers import get_notification_list, get_num_to_fetch
103
from django.http import JsonResponse
104
105
def custom_notification_api(request):
106
"""Custom API endpoint using helper functions."""
107
108
# Get validated number to fetch
109
num_to_fetch = get_num_to_fetch(request)
110
print(f"Fetching {num_to_fetch} notifications")
111
112
# Get formatted notification list
113
unread_notifications = get_notification_list(request, 'unread')
114
all_notifications = get_notification_list(request, 'all')
115
116
return JsonResponse({
117
'unread': unread_notifications,
118
'all': all_notifications,
119
'meta': {
120
'requested_count': num_to_fetch,
121
'unread_count': len(unread_notifications),
122
'all_count': len(all_notifications)
123
}
124
})
125
126
# Example request: /api/notifications/?max=25&mark_as_read=true
127
# Returns formatted notification data with auto-read functionality
128
```
129
130
#### Custom View with Helpers
131
132
```python
133
from django.shortcuts import render
134
from django.contrib.auth.decorators import login_required
135
from notifications.helpers import get_notification_list
136
137
@login_required
138
def dashboard_notifications(request):
139
"""Dashboard view showing formatted notifications."""
140
141
# Get recent notifications for display
142
recent_notifications = get_notification_list(request, 'all')[:5]
143
unread_notifications = get_notification_list(request, 'unread')
144
145
# Process notifications for template
146
processed_notifications = []
147
for notification in recent_notifications:
148
processed_notifications.append({
149
'id': notification['id'],
150
'display_text': f"{notification['actor']} {notification['verb']}",
151
'target_text': notification.get('target', ''),
152
'time_ago': notification['timestamp'],
153
'is_unread': notification['unread'],
154
'edit_url': f"/admin/notifications/notification/{notification['id']}/change/",
155
'mark_read_url': f"/notifications/mark-as-read/{notification['slug']}/"
156
})
157
158
return render(request, 'dashboard/notifications.html', {
159
'notifications': processed_notifications,
160
'unread_count': len(unread_notifications)
161
})
162
```
163
164
#### Slug Conversion Examples
165
166
```python
167
from notifications.utils import id2slug, slug2id
168
from notifications.models import Notification
169
170
# Convert ID to slug for URL
171
notification = Notification.objects.get(id=123)
172
url_slug = id2slug(notification.id)
173
print(f"URL slug: {url_slug}") # Output: 111032
174
175
# Use in URL pattern
176
notification_url = f"/notifications/mark-as-read/{url_slug}/"
177
178
# Convert slug back to ID for database lookup
179
def mark_notification_read(request, slug):
180
notification_id = slug2id(slug)
181
notification = Notification.objects.get(
182
id=notification_id,
183
recipient=request.user
184
)
185
notification.mark_as_read()
186
return redirect('notifications:all')
187
188
# Bulk slug operations
189
notification_ids = [100, 101, 102, 103]
190
slugs = [id2slug(nid) for nid in notification_ids]
191
print(f"Slugs: {slugs}") # [111009, 111010, 111011, 111012]
192
193
# Convert back
194
original_ids = [slug2id(slug) for slug in slugs]
195
print(f"Original IDs: {original_ids}") # [100, 101, 102, 103]
196
```
197
198
#### Request Parameter Processing
199
200
```python
201
from notifications.helpers import get_num_to_fetch
202
203
def process_notification_request(request):
204
"""Demonstrate request parameter processing."""
205
206
# Various request scenarios
207
test_requests = [
208
{'GET': {}}, # Default: 10
209
{'GET': {'max': '25'}}, # Valid: 25
210
{'GET': {'max': '150'}}, # Too large: 10 (default)
211
{'GET': {'max': '0'}}, # Too small: 10 (default)
212
{'GET': {'max': 'invalid'}}, # Invalid: 10 (default)
213
{'GET': {'max': '50'}}, # Valid: 50
214
]
215
216
results = []
217
for req_data in test_requests:
218
# Mock request object
219
class MockRequest:
220
def __init__(self, get_data):
221
self.GET = get_data
222
223
mock_request = MockRequest(req_data['GET'])
224
num_to_fetch = get_num_to_fetch(mock_request)
225
results.append({
226
'input': req_data['GET'].get('max', 'not provided'),
227
'output': num_to_fetch
228
})
229
230
return results
231
232
# Example output:
233
# [
234
# {'input': 'not provided', 'output': 10},
235
# {'input': '25', 'output': 25},
236
# {'input': '150', 'output': 10},
237
# {'input': '0', 'output': 10},
238
# {'input': 'invalid', 'output': 10},
239
# {'input': '50', 'output': 50}
240
# ]
241
```
242
243
#### Custom Notification Formatter
244
245
```python
246
from notifications.helpers import get_notification_list
247
from django.contrib.humanize.templatetags.humanize import naturaltime
248
249
def format_notifications_for_email(user, max_notifications=20):
250
"""Format notifications for email digest."""
251
252
# Create mock request for helper function
253
class MockRequest:
254
def __init__(self, user, max_count):
255
self.user = user
256
self.GET = {'max': str(max_count)}
257
258
mock_request = MockRequest(user, max_notifications)
259
notifications = get_notification_list(mock_request, 'unread')
260
261
formatted_notifications = []
262
for notification in notifications:
263
formatted_notifications.append({
264
'subject': f"New notification: {notification['verb']}",
265
'message': notification.get('description',
266
f"{notification['actor']} {notification['verb']}"),
267
'time': naturaltime(notification['timestamp']),
268
'actor': notification['actor'],
269
'action': notification['verb'],
270
'target': notification.get('target'),
271
'url': f"https://example.com/notifications/mark-as-read/{notification['slug']}/"
272
})
273
274
return formatted_notifications
275
276
# Usage
277
user_notifications = format_notifications_for_email(user, 10)
278
for notif in user_notifications:
279
print(f"Email: {notif['subject']}")
280
print(f"Content: {notif['message']}")
281
print(f"Time: {notif['time']}")
282
print("---")
283
```
284
285
#### Pagination Helper
286
287
```python
288
from notifications.helpers import get_num_to_fetch
289
from django.core.paginator import Paginator
290
291
def paginated_notifications(request, method_name='all'):
292
"""Get paginated notifications using helper functions."""
293
294
# Get number to fetch per page
295
per_page = get_num_to_fetch(request)
296
297
# Get user's notifications
298
if method_name == 'unread':
299
notifications = request.user.notifications.unread()
300
elif method_name == 'read':
301
notifications = request.user.notifications.read()
302
else:
303
notifications = request.user.notifications.all()
304
305
# Create paginator
306
paginator = Paginator(notifications, per_page)
307
page_number = request.GET.get('page', 1)
308
page_obj = paginator.get_page(page_number)
309
310
# Format notifications for response
311
formatted_notifications = []
312
for notification in page_obj:
313
formatted_notifications.append({
314
'id': notification.id,
315
'slug': notification.slug,
316
'actor': str(notification.actor),
317
'verb': notification.verb,
318
'target': str(notification.target) if notification.target else None,
319
'description': notification.description,
320
'timestamp': notification.timestamp,
321
'unread': notification.unread,
322
'level': notification.level
323
})
324
325
return {
326
'notifications': formatted_notifications,
327
'pagination': {
328
'has_previous': page_obj.has_previous(),
329
'has_next': page_obj.has_next(),
330
'previous_page_number': page_obj.previous_page_number() if page_obj.has_previous() else None,
331
'next_page_number': page_obj.next_page_number() if page_obj.has_next() else None,
332
'current_page': page_obj.number,
333
'total_pages': page_obj.paginator.num_pages,
334
'total_count': page_obj.paginator.count,
335
'per_page': per_page
336
}
337
}
338
339
# Usage in view
340
def notification_list_api(request):
341
result = paginated_notifications(request, 'unread')
342
return JsonResponse(result)
343
```
344
345
#### Bulk Operations with Utilities
346
347
```python
348
from notifications.utils import slug2id
349
from notifications.models import Notification
350
351
def bulk_mark_notifications_read(request):
352
"""Mark multiple notifications as read using slugs."""
353
354
# Get slugs from request (e.g., form data or JSON)
355
slugs = request.POST.getlist('notification_slugs')
356
# or from JSON: slugs = json.loads(request.body).get('slugs', [])
357
358
# Convert slugs to IDs
359
notification_ids = [slug2id(slug) for slug in slugs]
360
361
# Bulk update notifications
362
updated_count = Notification.objects.filter(
363
id__in=notification_ids,
364
recipient=request.user,
365
unread=True
366
).update(unread=False)
367
368
return JsonResponse({
369
'success': True,
370
'updated_count': updated_count,
371
'processed_ids': notification_ids
372
})
373
374
def generate_notification_urls(notifications):
375
"""Generate URLs for a list of notifications."""
376
377
urls = {}
378
for notification in notifications:
379
slug = notification.slug # Uses property from model
380
urls[notification.id] = {
381
'mark_read': f"/notifications/mark-as-read/{slug}/",
382
'mark_unread': f"/notifications/mark-as-unread/{slug}/",
383
'delete': f"/notifications/delete/{slug}/",
384
'detail': f"/notifications/{slug}/"
385
}
386
387
return urls
388
389
# Example usage
390
user_notifications = user.notifications.unread()[:10]
391
notification_urls = generate_notification_urls(user_notifications)
392
393
for notification in user_notifications:
394
urls = notification_urls[notification.id]
395
print(f"Notification {notification.id}:")
396
print(f" Mark Read: {urls['mark_read']}")
397
print(f" Delete: {urls['delete']}")
398
```