You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: Improve performance by not always prefetching channels and target
This fixed performance for the common use case where people don't use Notification.target to dynamically generate the notification text. By always prefetching the `target` field, it was a performance penalty for everyone. Now you need to explicitly prefetch the target field yourself. See performance.md for more information.
Always prefetching the channels relationship didn't make sense since users don't normally display these fields.
Copy file name to clipboardExpand all lines: docs/performance.md
+11-7Lines changed: 11 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,14 @@
4
4
5
5
The `target` field is a GenericForeignKey that can point to any Django model instance. While convenient, accessing targets requires careful consideration for performance.
6
6
7
-
When using Django 5.0+, this library automatically includes `.prefetch_related("target")` when using the standard query methods. This efficiently fetches target objects, but only the _direct_ targets - accessing relationships _through_the target will still cause additional queries.
7
+
By default, the library does **not** prefetch targets to avoid unnecessary queries when they're not needed. If you need to access the target field, you should explicitly prefetch it:
8
8
9
-
_On Django 4.2, you'll need to manually deal with prefetching the `target` relationship._
Note that this only fetches the _direct_ targets - accessing relationships _through_ the target will still cause additional queries.
10
15
11
16
Consider this problematic example that will cause N+1 queries:
12
17
@@ -37,10 +42,10 @@ class CommentNotificationType(NotificationType):
37
42
returnf'{actor_name} commented on your article "{article.title}": "{comment_text}"'
38
43
```
39
44
40
-
When displaying a list of 10 notifications, this will execute:
45
+
When displaying a list of 10 notifications, with `.prefetch_related("target")` applied, this will execute:
41
46
42
47
- 1 query for the notifications
43
-
- 1 query for the target comments (Django 5.0+ only, automatically prefetched)
48
+
- 1 query for the target comments
44
49
- 10 queries for the articles (N+1 problem!)
45
50
46
51
#### Solution 1: store data in the notification
@@ -59,15 +64,14 @@ send_notification(
59
64
)
60
65
```
61
66
62
-
However, this only works if you don’t need to dynamically generate the text - for example to make sure the text is always up to date, or to deal with internationalization.
67
+
However, this only works if you don’t need to dynamically generate the text - for example to make sure the text is always up to date, or to deal with [internationalization](https://github.com/loopwerk/django-generic-notifications/blob/main/docs/multilingual.md).
63
68
64
69
#### Solution 2: prefetch deeper relationships
65
70
66
71
If you must access relationships through the target, you can prefetch them:
67
72
68
73
```python
69
-
# On Django 5.0+ the library already prefetches targets,
70
-
# but you need to add deeper relationships yourself
74
+
# Prefetch the article relationship through target
Copy file name to clipboardExpand all lines: pyproject.toml
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
[project]
2
2
name = "django-generic-notifications"
3
-
version = "2.0.0"
3
+
version = "2.0.1"
4
4
description = "A flexible, multi-channel notification system for Django applications with built-in support for email digests, user preferences, and extensible delivery channels."
0 commit comments