0
# Admin Integration
1
2
Admin interface configuration for managing notifications with proper field displays, filtering options, and bulk actions for administrative oversight and debugging.
3
4
## Capabilities
5
6
### Notification Admin Classes
7
8
Django admin configuration classes for managing notifications in the Django admin interface.
9
10
```python { .api }
11
class AbstractNotificationAdmin(admin.ModelAdmin):
12
"""Base admin class for notification models."""
13
raw_id_fields = ('recipient',)
14
list_display = ('recipient', 'actor', 'level', 'target', 'unread', 'public')
15
list_filter = ('level', 'unread', 'public', 'timestamp')
16
17
def get_queryset(self, request):
18
"""
19
Optimize queryset with prefetch_related for better performance.
20
21
Args:
22
request: Django admin request object
23
24
Returns:
25
QuerySet: Optimized queryset with prefetched actors
26
"""
27
28
class NotificationAdmin(AbstractNotificationAdmin):
29
"""Concrete admin class for Notification model."""
30
raw_id_fields = ('recipient',)
31
readonly_fields = ('action_object_url', 'actor_object_url', 'target_object_url')
32
list_display = ('recipient', 'actor', 'level', 'target', 'unread', 'public')
33
list_filter = ('level', 'unread', 'public', 'timestamp')
34
actions = [mark_unread]
35
36
def get_queryset(self, request):
37
"""
38
Get optimized queryset for admin display.
39
40
Args:
41
request: Django admin request object
42
43
Returns:
44
QuerySet: Notifications with prefetched related objects
45
"""
46
```
47
48
### Admin Actions
49
50
Custom admin actions for bulk operations on notifications.
51
52
```python { .api }
53
def mark_unread(modeladmin, request, queryset):
54
"""
55
Admin action to mark selected notifications as unread.
56
57
Args:
58
modeladmin: Admin model instance
59
request: Django admin request object
60
queryset: Selected notification objects
61
62
Returns:
63
None: Updates notifications in place
64
65
Description:
66
Bulk action that sets unread=True for selected notifications
67
"""
68
```
69
70
### Usage Examples
71
72
#### Custom Admin Configuration
73
74
```python
75
# In your admin.py
76
from django.contrib import admin
77
from django.utils.translation import gettext_lazy as _
78
from notifications.models import Notification
79
from notifications.admin import NotificationAdmin as BaseNotificationAdmin
80
81
# Extend the base admin class
82
class CustomNotificationAdmin(BaseNotificationAdmin):
83
# Add more fields to list display
84
list_display = (
85
'recipient',
86
'actor',
87
'verb',
88
'level',
89
'target',
90
'unread',
91
'public',
92
'timestamp',
93
'get_description_preview'
94
)
95
96
# Add more filter options
97
list_filter = (
98
'level',
99
'unread',
100
'public',
101
'timestamp',
102
'deleted',
103
'emailed'
104
)
105
106
# Enable search
107
search_fields = (
108
'recipient__username',
109
'recipient__email',
110
'verb',
111
'description'
112
)
113
114
# Add readonly fields
115
readonly_fields = (
116
'action_object_url',
117
'actor_object_url',
118
'target_object_url',
119
'timestamp',
120
'slug'
121
)
122
123
# Organize fields in fieldsets
124
fieldsets = (
125
('Basic Information', {
126
'fields': ('recipient', 'level', 'unread', 'public')
127
}),
128
('Activity Details', {
129
'fields': ('actor_content_type', 'actor_object_id', 'verb', 'description')
130
}),
131
('Related Objects', {
132
'fields': ('target_content_type', 'target_object_id', 'action_object_content_type', 'action_object_object_id'),
133
'classes': ('collapse',)
134
}),
135
('Metadata', {
136
'fields': ('timestamp', 'deleted', 'emailed', 'data'),
137
'classes': ('collapse',)
138
}),
139
('Admin Links', {
140
'fields': ('actor_object_url', 'target_object_url', 'action_object_url'),
141
'classes': ('collapse',)
142
})
143
)
144
145
# Custom methods for display
146
def get_description_preview(self, obj):
147
"""Show truncated description in list view."""
148
if obj.description:
149
return obj.description[:50] + '...' if len(obj.description) > 50 else obj.description
150
return '-'
151
get_description_preview.short_description = 'Description'
152
153
def get_actor_type(self, obj):
154
"""Show actor content type."""
155
return obj.actor_content_type.model
156
get_actor_type.short_description = 'Actor Type'
157
158
# Add custom actions
159
actions = ['mark_unread', 'mark_read', 'soft_delete', 'mark_as_sent']
160
161
def mark_read(self, request, queryset):
162
"""Mark selected notifications as read."""
163
updated = queryset.update(unread=False)
164
self.message_user(request, f'{updated} notifications marked as read.')
165
mark_read.short_description = 'Mark selected notifications as read'
166
167
def soft_delete(self, request, queryset):
168
"""Soft delete selected notifications."""
169
updated = queryset.update(deleted=True)
170
self.message_user(request, f'{updated} notifications soft deleted.')
171
soft_delete.short_description = 'Soft delete selected notifications'
172
173
def mark_as_sent(self, request, queryset):
174
"""Mark selected notifications as emailed."""
175
updated = queryset.update(emailed=True)
176
self.message_user(request, f'{updated} notifications marked as sent.')
177
mark_as_sent.short_description = 'Mark selected notifications as emailed'
178
179
# Unregister the default admin and register custom one
180
admin.site.unregister(Notification)
181
admin.site.register(Notification, CustomNotificationAdmin)
182
```
183
184
#### Read-Only Admin for Analytics
185
186
```python
187
from django.contrib import admin
188
from notifications.models import Notification
189
190
class NotificationAnalyticsAdmin(admin.ModelAdmin):
191
"""Read-only admin for analytics and reporting."""
192
193
list_display = (
194
'id',
195
'recipient',
196
'actor',
197
'verb',
198
'level',
199
'timestamp',
200
'unread',
201
'get_time_since_created'
202
)
203
204
list_filter = (
205
'level',
206
'unread',
207
'public',
208
'timestamp',
209
('timestamp', admin.DateFieldListFilter),
210
)
211
212
search_fields = ('recipient__username', 'verb', 'description')
213
214
# Make it read-only
215
def has_add_permission(self, request):
216
return False
217
218
def has_change_permission(self, request, obj=None):
219
return False
220
221
def has_delete_permission(self, request, obj=None):
222
return False
223
224
def get_time_since_created(self, obj):
225
"""Show time since notification was created."""
226
return obj.timesince()
227
get_time_since_created.short_description = 'Age'
228
229
# Add date hierarchy for easy browsing
230
date_hierarchy = 'timestamp'
231
232
# Show more items per page
233
list_per_page = 50
234
235
# Register as separate admin interface
236
admin.site.register(Notification, NotificationAnalyticsAdmin, name='notification_analytics')
237
```
238
239
#### Inline Admin for Related Models
240
241
```python
242
from django.contrib import admin
243
from notifications.models import Notification
244
245
class NotificationInline(admin.TabularInline):
246
"""Inline admin for showing notifications on related models."""
247
model = Notification
248
extra = 0
249
readonly_fields = ('timestamp', 'level', 'verb', 'unread')
250
fields = ('timestamp', 'level', 'verb', 'unread', 'description')
251
252
def has_add_permission(self, request, obj=None):
253
return False
254
255
# Add to User admin
256
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
257
from django.contrib.auth.models import User
258
259
class UserAdmin(BaseUserAdmin):
260
inlines = [NotificationInline]
261
262
admin.site.unregister(User)
263
admin.site.register(User, UserAdmin)
264
```
265
266
#### Advanced Filtering
267
268
```python
269
from django.contrib import admin
270
from django.utils.translation import gettext_lazy as _
271
272
class UnreadFilter(admin.SimpleListFilter):
273
"""Custom filter for unread status."""
274
title = _('read status')
275
parameter_name = 'read_status'
276
277
def lookups(self, request, model_admin):
278
return (
279
('unread', _('Unread')),
280
('read', _('Read')),
281
('recent_unread', _('Unread (last 7 days)')),
282
)
283
284
def queryset(self, request, queryset):
285
if self.value() == 'unread':
286
return queryset.filter(unread=True)
287
elif self.value() == 'read':
288
return queryset.filter(unread=False)
289
elif self.value() == 'recent_unread':
290
from django.utils import timezone
291
from datetime import timedelta
292
week_ago = timezone.now() - timedelta(days=7)
293
return queryset.filter(unread=True, timestamp__gte=week_ago)
294
295
class ActorTypeFilter(admin.SimpleListFilter):
296
"""Filter by actor model type."""
297
title = _('actor type')
298
parameter_name = 'actor_type'
299
300
def lookups(self, request, model_admin):
301
# Get unique actor content types
302
from django.contrib.contenttypes.models import ContentType
303
actor_types = Notification.objects.values_list(
304
'actor_content_type', flat=True
305
).distinct()
306
307
return [
308
(ct_id, ContentType.objects.get(id=ct_id).model.title())
309
for ct_id in actor_types
310
]
311
312
def queryset(self, request, queryset):
313
if self.value():
314
return queryset.filter(actor_content_type=self.value())
315
316
class CustomNotificationAdmin(admin.ModelAdmin):
317
list_filter = (
318
UnreadFilter,
319
ActorTypeFilter,
320
'level',
321
'public',
322
'timestamp'
323
)
324
```
325
326
#### Bulk Data Management
327
328
```python
329
from django.contrib import admin
330
from django.http import HttpResponse
331
import csv
332
333
class NotificationDataAdmin(admin.ModelAdmin):
334
"""Admin with data export and bulk management features."""
335
336
actions = [
337
'export_as_csv',
338
'bulk_mark_read',
339
'bulk_soft_delete',
340
'cleanup_old_notifications'
341
]
342
343
def export_as_csv(self, request, queryset):
344
"""Export selected notifications as CSV."""
345
response = HttpResponse(content_type='text/csv')
346
response['Content-Disposition'] = 'attachment; filename="notifications.csv"'
347
348
writer = csv.writer(response)
349
writer.writerow([
350
'ID', 'Recipient', 'Actor', 'Verb', 'Level',
351
'Timestamp', 'Unread', 'Description'
352
])
353
354
for notification in queryset:
355
writer.writerow([
356
notification.id,
357
notification.recipient.username,
358
str(notification.actor),
359
notification.verb,
360
notification.level,
361
notification.timestamp,
362
notification.unread,
363
notification.description or ''
364
])
365
366
return response
367
export_as_csv.short_description = 'Export selected notifications as CSV'
368
369
def bulk_mark_read(self, request, queryset):
370
"""Mark all selected notifications as read."""
371
count = queryset.filter(unread=True).update(unread=False)
372
self.message_user(request, f'{count} notifications marked as read.')
373
bulk_mark_read.short_description = 'Mark selected as read'
374
375
def bulk_soft_delete(self, request, queryset):
376
"""Soft delete selected notifications."""
377
count = queryset.update(deleted=True)
378
self.message_user(request, f'{count} notifications soft deleted.')
379
bulk_soft_delete.short_description = 'Soft delete selected'
380
381
def cleanup_old_notifications(self, request, queryset):
382
"""Delete notifications older than 30 days."""
383
from django.utils import timezone
384
from datetime import timedelta
385
386
cutoff_date = timezone.now() - timedelta(days=30)
387
old_notifications = queryset.filter(timestamp__lt=cutoff_date)
388
count = old_notifications.count()
389
old_notifications.delete()
390
391
self.message_user(request, f'{count} old notifications deleted.')
392
cleanup_old_notifications.short_description = 'Delete notifications older than 30 days'
393
```
394
395
#### Permission-Based Admin
396
397
```python
398
from django.contrib import admin
399
400
class PermissionBasedNotificationAdmin(admin.ModelAdmin):
401
"""Admin with permission-based access control."""
402
403
def get_queryset(self, request):
404
"""Filter notifications based on user permissions."""
405
qs = super().get_queryset(request)
406
407
if request.user.is_superuser:
408
return qs
409
elif request.user.has_perm('notifications.view_all_notifications'):
410
return qs
411
else:
412
# Only show notifications for users the admin can manage
413
managed_users = self.get_managed_users(request.user)
414
return qs.filter(recipient__in=managed_users)
415
416
def get_managed_users(self, admin_user):
417
"""Get users this admin can manage."""
418
# Example: staff can manage users in their department
419
if hasattr(admin_user, 'department'):
420
return admin_user.department.users.all()
421
return []
422
423
def has_change_permission(self, request, obj=None):
424
"""Check if user can change specific notification."""
425
if not super().has_change_permission(request, obj):
426
return False
427
428
if obj and not request.user.is_superuser:
429
# Check if admin can manage this notification's recipient
430
managed_users = self.get_managed_users(request.user)
431
return obj.recipient in managed_users
432
433
return True
434
```
435
436
#### Integration with Custom Models
437
438
```python
439
from django.contrib import admin
440
from myapp.models import BlogPost
441
from notifications.models import Notification
442
443
class BlogPostAdmin(admin.ModelAdmin):
444
"""Blog post admin with notification management."""
445
446
def save_model(self, request, obj, form, change):
447
"""Send notification when blog post is published."""
448
super().save_model(request, obj, form, change)
449
450
if not change and obj.status == 'published':
451
# Send notification to followers
452
from notifications.signals import notify
453
followers = obj.author.followers.all()
454
455
notify.send(
456
sender=obj.author,
457
recipient=followers,
458
verb='published new post',
459
target=obj,
460
description=f'New blog post: {obj.title}'
461
)
462
463
self.message_user(
464
request,
465
f'Post published and {followers.count()} followers notified.'
466
)
467
468
def get_notification_count(self, obj):
469
"""Show notification count for this post."""
470
return Notification.objects.filter(
471
target_content_type__model='blogpost',
472
target_object_id=obj.id
473
).count()
474
get_notification_count.short_description = 'Notifications'
475
476
admin.site.register(BlogPost, BlogPostAdmin)
477
```