0
# Core Notification System
1
2
The foundational notification models, queryset methods, and signal handling that power the entire django-notifications-hq system. This includes the main Notification model with fields for actor, verb, target, timestamps, and read status.
3
4
## Capabilities
5
6
### Notification Model
7
8
The main notification model that extends AbstractNotification with additional humanization methods for displaying time information.
9
10
```python { .api }
11
class Notification(AbstractNotification):
12
def naturalday(self):
13
"""
14
Return human-readable day format for notification timestamp.
15
16
Returns:
17
str: 'today', 'yesterday', or date string
18
"""
19
20
def naturaltime(self):
21
"""
22
Return human-readable relative time for notification timestamp.
23
24
Returns:
25
str: '2 hours ago', 'just now', etc.
26
"""
27
28
class Meta(AbstractNotification.Meta):
29
abstract = False
30
swappable = swappable_setting('notifications', 'Notification')
31
```
32
33
### Abstract Notification Model
34
35
The base notification model containing all core functionality for activity tracking with actor-verb-object patterns.
36
37
```python { .api }
38
class AbstractNotification(models.Model):
39
"""
40
Activity model describing actor acting out a verb on optional target.
41
Based on Activity Streams specification.
42
43
Format patterns:
44
- <actor> <verb> <time>
45
- <actor> <verb> <target> <time>
46
- <actor> <verb> <action_object> <target> <time>
47
"""
48
49
# Core fields
50
level = models.CharField(max_length=20, choices=LEVELS, default='info')
51
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
52
unread = models.BooleanField(default=True, db_index=True)
53
verb = models.CharField(max_length=255)
54
description = models.TextField(blank=True, null=True)
55
timestamp = models.DateTimeField(default=timezone.now, db_index=True)
56
public = models.BooleanField(default=True, db_index=True)
57
deleted = models.BooleanField(default=False, db_index=True)
58
emailed = models.BooleanField(default=False, db_index=True)
59
data = JSONField(blank=True, null=True)
60
61
# Generic foreign key fields for actor
62
actor_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
63
actor_object_id = models.CharField(max_length=255)
64
actor = GenericForeignKey('actor_content_type', 'actor_object_id')
65
66
# Generic foreign key fields for target (optional)
67
target_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
68
target_object_id = models.CharField(max_length=255, blank=True, null=True)
69
target = GenericForeignKey('target_content_type', 'target_object_id')
70
71
# Generic foreign key fields for action object (optional)
72
action_object_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
73
action_object_object_id = models.CharField(max_length=255, blank=True, null=True)
74
action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id')
75
76
objects = NotificationQuerySet.as_manager()
77
78
def __str__(self):
79
"""
80
String representation following activity stream patterns.
81
82
Returns:
83
str: Formatted notification string with actor, verb, objects, and time
84
"""
85
86
def timesince(self, now=None):
87
"""
88
Time since notification creation using Django's timesince utility.
89
90
Args:
91
now (datetime, optional): Reference time for calculation
92
93
Returns:
94
str: Relative time string
95
"""
96
97
@property
98
def slug(self):
99
"""
100
URL-safe slug for notification identification.
101
102
Returns:
103
int: Notification ID converted to URL slug
104
"""
105
106
def mark_as_read(self):
107
"""Mark notification as read if currently unread."""
108
109
def mark_as_unread(self):
110
"""Mark notification as unread if currently read."""
111
112
def actor_object_url(self):
113
"""
114
Generate admin URL for the actor object.
115
116
Returns:
117
str: HTML link to admin change page or plain ID
118
"""
119
120
def action_object_url(self):
121
"""
122
Generate admin URL for the action object.
123
124
Returns:
125
str: HTML link to admin change page or plain ID
126
"""
127
128
def target_object_url(self):
129
"""
130
Generate admin URL for the target object.
131
132
Returns:
133
str: HTML link to admin change page or plain ID
134
"""
135
136
class Meta:
137
abstract = True
138
ordering = ('-timestamp',)
139
index_together = ('recipient', 'unread')
140
verbose_name = 'Notification'
141
verbose_name_plural = 'Notifications'
142
```
143
144
### Notification QuerySet
145
146
Custom queryset providing notification-specific filtering and bulk operations for efficient database queries and notification management.
147
148
```python { .api }
149
class NotificationQuerySet(models.query.QuerySet):
150
"""Custom queryset with notification-specific methods."""
151
152
def unsent(self):
153
"""
154
Filter notifications that haven't been emailed.
155
156
Returns:
157
QuerySet: Notifications with emailed=False
158
"""
159
160
def sent(self):
161
"""
162
Filter notifications that have been emailed.
163
164
Returns:
165
QuerySet: Notifications with emailed=True
166
"""
167
168
def unread(self, include_deleted=False):
169
"""
170
Filter unread notifications.
171
172
Args:
173
include_deleted (bool): Whether to include soft-deleted notifications
174
175
Returns:
176
QuerySet: Unread notifications
177
"""
178
179
def read(self, include_deleted=False):
180
"""
181
Filter read notifications.
182
183
Args:
184
include_deleted (bool): Whether to include soft-deleted notifications
185
186
Returns:
187
QuerySet: Read notifications
188
"""
189
190
def mark_all_as_read(self, recipient=None):
191
"""
192
Mark all notifications in queryset as read.
193
194
Args:
195
recipient (User, optional): Filter by specific recipient
196
197
Returns:
198
int: Number of notifications updated
199
"""
200
201
def mark_all_as_unread(self, recipient=None):
202
"""
203
Mark all notifications in queryset as unread.
204
205
Args:
206
recipient (User, optional): Filter by specific recipient
207
208
Returns:
209
int: Number of notifications updated
210
"""
211
212
def deleted(self):
213
"""
214
Filter soft-deleted notifications.
215
216
Returns:
217
QuerySet: Notifications with deleted=True
218
219
Raises:
220
ImproperlyConfigured: If SOFT_DELETE setting is False
221
"""
222
223
def active(self):
224
"""
225
Filter active (non-deleted) notifications.
226
227
Returns:
228
QuerySet: Notifications with deleted=False
229
230
Raises:
231
ImproperlyConfigured: If SOFT_DELETE setting is False
232
"""
233
234
def mark_all_as_deleted(self, recipient=None):
235
"""
236
Soft delete all notifications in queryset.
237
238
Args:
239
recipient (User, optional): Filter by specific recipient
240
241
Returns:
242
int: Number of notifications updated
243
244
Raises:
245
ImproperlyConfigured: If SOFT_DELETE setting is False
246
"""
247
248
def mark_all_as_active(self, recipient=None):
249
"""
250
Restore all notifications in queryset from soft deletion.
251
252
Args:
253
recipient (User, optional): Filter by specific recipient
254
255
Returns:
256
int: Number of notifications updated
257
258
Raises:
259
ImproperlyConfigured: If SOFT_DELETE setting is False
260
"""
261
262
def mark_as_unsent(self, recipient=None):
263
"""
264
Mark notifications as not emailed.
265
266
Args:
267
recipient (User, optional): Filter by specific recipient
268
269
Returns:
270
int: Number of notifications updated
271
"""
272
273
def mark_as_sent(self, recipient=None):
274
"""
275
Mark notifications as emailed.
276
277
Args:
278
recipient (User, optional): Filter by specific recipient
279
280
Returns:
281
int: Number of notifications updated
282
"""
283
```
284
285
### Notification Levels
286
287
```python { .api }
288
LEVELS = Choices('success', 'info', 'warning', 'error')
289
```
290
291
### Usage Examples
292
293
#### Creating and Querying Notifications
294
295
```python
296
from django.contrib.auth.models import User
297
from notifications.models import Notification
298
299
# Get user notifications
300
user = User.objects.get(username='jane')
301
302
# Query unread notifications
303
unread = user.notifications.unread()
304
305
# Query read notifications
306
read = user.notifications.read()
307
308
# Mark all as read
309
user.notifications.mark_all_as_read()
310
311
# Query by level
312
info_notifications = user.notifications.filter(level='info')
313
314
# Check if notification exists
315
has_unread = user.notifications.unread().exists()
316
317
# Get notification count
318
unread_count = user.notifications.unread().count()
319
320
# Access notification details
321
for notification in user.notifications.all()[:5]:
322
print(f"{notification.actor} {notification.verb}")
323
print(f"Time: {notification.naturaltime()}")
324
print(f"Description: {notification.description}")
325
if notification.target:
326
print(f"Target: {notification.target}")
327
```
328
329
#### Individual Notification Management
330
331
```python
332
# Get specific notification
333
notification = Notification.objects.get(id=123)
334
335
# Mark as read/unread
336
notification.mark_as_read()
337
notification.mark_as_unread()
338
339
# Access related objects
340
actor = notification.actor
341
target = notification.target
342
action_object = notification.action_object
343
344
# Get formatted time
345
time_ago = notification.timesince()
346
natural_day = notification.naturalday()
347
348
# Check properties
349
is_unread = notification.unread
350
is_public = notification.public
351
level = notification.level
352
```