or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-integration.mdapi-endpoints.mdconfiguration.mdcore-system.mdindex.mdsignals.mdtemplate-integration.mdutilities.mdweb-interface.md

core-system.mddocs/

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

```