0
# Template Integration
1
2
Django template tags for displaying notification counts, status indicators, and live-updating notification interfaces with JavaScript integration for real-time updates.
3
4
## Capabilities
5
6
### Template Tags
7
8
Django template tags for displaying notification information and generating JavaScript for live updates.
9
10
```python { .api }
11
@register.simple_tag(takes_context=True)
12
def notifications_unread(context):
13
"""
14
Get unread notification count for current user (cached).
15
16
Args:
17
context: Django template context containing request and user
18
19
Returns:
20
int: Number of unread notifications for authenticated user, 0 for anonymous
21
22
Template usage:
23
{% notifications_unread %}
24
{% notifications_unread as count %}
25
"""
26
27
@register.filter
28
def has_notification(user):
29
"""
30
Check if user has any unread notifications.
31
32
Args:
33
user: Django User object
34
35
Returns:
36
bool: True if user has unread notifications, False otherwise
37
38
Template usage:
39
{{ user|has_notification }}
40
{% if user|has_notification %}...{% endif %}
41
"""
42
43
@register.simple_tag
44
def register_notify_callbacks(
45
badge_class='live_notify_badge',
46
menu_class='live_notify_list',
47
refresh_period=15,
48
callbacks='',
49
api_name='list',
50
fetch=5,
51
nonce=None,
52
mark_as_read=False
53
):
54
"""
55
Generate JavaScript code for live notification functionality.
56
57
Args:
58
badge_class (str): CSS class for notification badge elements
59
menu_class (str): CSS class for notification list elements
60
refresh_period (int): Update interval in seconds
61
callbacks (str): Comma-separated callback function names
62
api_name (str): API endpoint type ('list' or 'count')
63
fetch (int): Number of notifications to fetch
64
nonce (str, optional): CSP nonce for script tag
65
mark_as_read (bool): Auto-mark notifications as read when fetched
66
67
Returns:
68
str: HTML script tag with JavaScript configuration
69
70
Template usage:
71
{% register_notify_callbacks %}
72
{% register_notify_callbacks refresh_period=30 fetch=10 %}
73
"""
74
75
@register.simple_tag(takes_context=True)
76
def live_notify_badge(context, badge_class='live_notify_badge'):
77
"""
78
Render live notification count badge.
79
80
Args:
81
context: Django template context
82
badge_class (str): CSS class for badge element
83
84
Returns:
85
str: HTML span element with current unread count
86
87
Template usage:
88
{% live_notify_badge %}
89
{% live_notify_badge "my-badge-class" %}
90
"""
91
92
@register.simple_tag
93
def live_notify_list(list_class='live_notify_list'):
94
"""
95
Render empty notification list container for JavaScript population.
96
97
Args:
98
list_class (str): CSS class for list container
99
100
Returns:
101
str: Empty HTML ul element for notifications
102
103
Template usage:
104
{% live_notify_list %}
105
{% live_notify_list "my-list-class" %}
106
"""
107
```
108
109
### Caching Function
110
111
```python { .api }
112
def get_cached_notification_unread_count(user):
113
"""
114
Get cached unread notification count for user.
115
116
Args:
117
user: Django User object
118
119
Returns:
120
int: Cached unread notification count
121
122
Note:
123
Uses Django cache with CACHE_TIMEOUT setting for cache duration
124
"""
125
```
126
127
### Usage Examples
128
129
#### Basic Template Integration
130
131
```html
132
<!-- Load the template tags -->
133
{% load notifications_tags %}
134
135
<!-- Simple unread count display -->
136
<div class="notifications">
137
Notifications ({% notifications_unread %})
138
</div>
139
140
<!-- Store count in variable -->
141
{% notifications_unread as unread_count %}
142
{% if unread_count > 0 %}
143
<div class="notification-alert">
144
You have {{ unread_count }} unread notification{{ unread_count|pluralize }}
145
</div>
146
{% endif %}
147
148
<!-- Check if user has notifications -->
149
{% if user|has_notification %}
150
<span class="notification-indicator">β</span>
151
{% endif %}
152
```
153
154
#### Navigation Bar Integration
155
156
```html
157
{% load notifications_tags %}
158
159
<nav class="navbar">
160
<ul class="nav-items">
161
<li class="nav-item">
162
<a href="{% url 'notifications:unread' %}" class="nav-link">
163
<i class="icon-bell"></i>
164
Notifications
165
{% notifications_unread as count %}
166
{% if count > 0 %}
167
<span class="badge badge-danger">{{ count }}</span>
168
{% endif %}
169
</a>
170
</li>
171
</ul>
172
</nav>
173
174
<!-- Dropdown notification menu -->
175
<div class="notification-dropdown">
176
<button class="dropdown-toggle" data-toggle="dropdown">
177
<i class="icon-bell"></i>
178
{% if user|has_notification %}
179
<span class="notification-dot"></span>
180
{% endif %}
181
</button>
182
<div class="dropdown-menu">
183
<div class="dropdown-header">
184
Notifications
185
<span class="count">{% notifications_unread %}</span>
186
</div>
187
<div class="notification-list" id="notification-dropdown-list">
188
<!-- Will be populated by JavaScript -->
189
</div>
190
<div class="dropdown-footer">
191
<a href="{% url 'notifications:all' %}">View All</a>
192
<a href="{% url 'notifications:mark_all_as_read' %}">Mark All as Read</a>
193
</div>
194
</div>
195
</div>
196
```
197
198
#### Live Notification Setup
199
200
```html
201
{% load notifications_tags %}
202
203
<!DOCTYPE html>
204
<html>
205
<head>
206
<title>My App</title>
207
<style>
208
.live_notify_badge {
209
background: red;
210
color: white;
211
border-radius: 50%;
212
padding: 2px 6px;
213
font-size: 12px;
214
position: absolute;
215
top: -8px;
216
right: -8px;
217
}
218
219
.live_notify_list {
220
max-height: 300px;
221
overflow-y: auto;
222
border: 1px solid #ddd;
223
border-radius: 4px;
224
}
225
226
.notification-item {
227
padding: 10px;
228
border-bottom: 1px solid #eee;
229
cursor: pointer;
230
}
231
232
.notification-item:hover {
233
background-color: #f5f5f5;
234
}
235
</style>
236
</head>
237
<body>
238
<div class="header">
239
<div class="notification-container" style="position: relative;">
240
<i class="icon-bell"></i>
241
<!-- Live badge that updates automatically -->
242
{% live_notify_badge %}
243
</div>
244
</div>
245
246
<div class="notification-panel">
247
<h3>Recent Notifications</h3>
248
<!-- Live list that updates automatically -->
249
{% live_notify_list %}
250
</div>
251
252
<!-- Register JavaScript for live updates -->
253
{% register_notify_callbacks refresh_period=20 fetch=8 %}
254
255
<!-- Custom callback functions -->
256
<script>
257
function onNotificationUpdate(data) {
258
console.log('Notifications updated:', data);
259
// Custom handling when notifications are updated
260
if (data.unread_count > 0) {
261
document.title = `(${data.unread_count}) My App`;
262
} else {
263
document.title = 'My App';
264
}
265
}
266
267
function onNotificationClick(notification) {
268
console.log('Notification clicked:', notification);
269
// Handle notification click
270
window.location.href = '/notification/' + notification.id;
271
}
272
</script>
273
274
<!-- Register callbacks -->
275
{% register_notify_callbacks callbacks="onNotificationUpdate,onNotificationClick" %}
276
</body>
277
</html>
278
```
279
280
#### Advanced Configuration
281
282
```html
283
{% load notifications_tags %}
284
285
<!-- Custom CSS classes and configuration -->
286
{% register_notify_callbacks
287
badge_class="my-notification-badge"
288
menu_class="my-notification-menu"
289
refresh_period=30
290
api_name="list"
291
fetch=15
292
mark_as_read=True
293
%}
294
295
<!-- Multiple notification areas -->
296
<div class="sidebar">
297
<h4>Quick Notifications</h4>
298
{% live_notify_list "sidebar-notifications" %}
299
</div>
300
301
<div class="main-content">
302
<div class="toolbar">
303
<span class="notification-icon">
304
π
305
{% live_notify_badge "toolbar-badge" %}
306
</span>
307
</div>
308
</div>
309
310
<!-- Configure different areas with different settings -->
311
<script>
312
// Custom configuration for sidebar
313
{% register_notify_callbacks
314
menu_class="sidebar-notifications"
315
fetch=5
316
refresh_period=60
317
%}
318
319
// Custom configuration for toolbar
320
{% register_notify_callbacks
321
badge_class="toolbar-badge"
322
api_name="count"
323
refresh_period=15
324
%}
325
</script>
326
```
327
328
#### CSP (Content Security Policy) Support
329
330
```html
331
{% load notifications_tags %}
332
333
<!-- Generate nonce for CSP -->
334
{% csrf_token %}
335
<script nonce="{{ csp_nonce }}">
336
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
337
</script>
338
339
<!-- Pass nonce to template tag -->
340
{% register_notify_callbacks nonce=csp_nonce %}
341
```
342
343
#### Conditional Loading
344
345
```html
346
{% load notifications_tags %}
347
348
<!-- Only load live notifications for authenticated users -->
349
{% if user.is_authenticated %}
350
<div class="user-notifications">
351
{% if user|has_notification %}
352
<div class="notification-alert">
353
You have new notifications!
354
{% live_notify_badge %}
355
</div>
356
{% endif %}
357
358
{% live_notify_list %}
359
{% register_notify_callbacks %}
360
</div>
361
{% else %}
362
<div class="guest-message">
363
<a href="{% url 'login' %}">Login</a> to see notifications
364
</div>
365
{% endif %}
366
```
367
368
#### Integration with Bootstrap
369
370
```html
371
{% load notifications_tags %}
372
373
<!-- Bootstrap navbar with notification dropdown -->
374
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
375
<div class="navbar-nav ms-auto">
376
<div class="nav-item dropdown">
377
<a class="nav-link dropdown-toggle position-relative" href="#" data-bs-toggle="dropdown">
378
<i class="fas fa-bell"></i>
379
{% live_notify_badge "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" %}
380
</a>
381
<div class="dropdown-menu dropdown-menu-end" style="width: 300px;">
382
<h6 class="dropdown-header">
383
Notifications
384
<span class="badge bg-primary ms-2">{% notifications_unread %}</span>
385
</h6>
386
<div class="dropdown-divider"></div>
387
<div class="notification-container" style="max-height: 400px; overflow-y: auto;">
388
{% live_notify_list "list-unstyled" %}
389
</div>
390
<div class="dropdown-divider"></div>
391
<div class="dropdown-item-text text-center">
392
<a href="{% url 'notifications:all' %}" class="btn btn-sm btn-outline-primary me-2">
393
View All
394
</a>
395
<a href="{% url 'notifications:mark_all_as_read' %}" class="btn btn-sm btn-outline-secondary">
396
Mark All Read
397
</a>
398
</div>
399
</div>
400
</div>
401
</div>
402
</nav>
403
404
<!-- Bootstrap styling for notifications -->
405
<style>
406
.list-unstyled .notification-item {
407
padding: 0.5rem 1rem;
408
border-bottom: 1px solid #dee2e6;
409
text-decoration: none;
410
color: inherit;
411
display: block;
412
}
413
414
.list-unstyled .notification-item:hover {
415
background-color: #f8f9fa;
416
}
417
418
.list-unstyled .notification-item:last-child {
419
border-bottom: none;
420
}
421
</style>
422
423
{% register_notify_callbacks
424
menu_class="list-unstyled"
425
badge_class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
426
refresh_period=25
427
fetch=10
428
%}
429
```
430
431
#### Custom Notification Rendering
432
433
```html
434
{% load notifications_tags %}
435
436
<!-- Override default notification rendering -->
437
<script>
438
function customNotificationRenderer(notifications) {
439
const container = document.querySelector('.live_notify_list');
440
container.innerHTML = '';
441
442
notifications.forEach(notification => {
443
const item = document.createElement('div');
444
item.className = 'notification-item';
445
item.innerHTML = `
446
<div class="notification-avatar">
447
<img src="/static/img/avatar-placeholder.png" alt="Avatar">
448
</div>
449
<div class="notification-content">
450
<div class="notification-text">
451
<strong>${notification.actor}</strong> ${notification.verb}
452
${notification.target ? notification.target : ''}
453
</div>
454
<div class="notification-time">
455
${formatTimeAgo(notification.timestamp)}
456
</div>
457
</div>
458
<div class="notification-actions">
459
<button onclick="markAsRead(${notification.slug})" class="btn-sm">β</button>
460
<button onclick="deleteNotification(${notification.slug})" class="btn-sm">β</button>
461
</div>
462
`;
463
container.appendChild(item);
464
});
465
}
466
467
// Override the default render function
468
window.renderNotifications = customNotificationRenderer;
469
</script>
470
471
{% live_notify_list %}
472
{% register_notify_callbacks callbacks="customNotificationRenderer" %}
473
```
474
475
### Helper Functions
476
477
Internal helper functions used by template tags for user context handling and caching.
478
479
```python { .api }
480
def get_cached_notification_unread_count(user):
481
"""
482
Get cached unread notification count for user with configurable timeout.
483
484
Args:
485
user: Django User object
486
487
Returns:
488
int: Number of unread notifications (cached result)
489
490
Cache key: 'cache_notification_unread_count'
491
Cache timeout: Configured via CACHE_TIMEOUT setting
492
"""
493
494
def user_context(context):
495
"""
496
Extract authenticated user from template context.
497
498
Args:
499
context: Django template context dict
500
501
Returns:
502
User: Authenticated user object or None for anonymous/missing users
503
504
Handles:
505
- Missing user in context
506
- Anonymous users (both Django < 1.11 and >= 1.11 syntax)
507
- Authenticated users
508
"""
509
```