Opened 4 weeks ago
Closed 3 weeks ago
#36741 closed Cleanup/optimization (fixed)
Link to discussion about Model.save() not being bulk-friendly from bulk_update() caveats
| Reported by: | Lam Phung | Owned by: | Youngkwang Yang |
|---|---|---|---|
| Component: | Documentation | Version: | 5.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Youngkwang Yang | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The documentation for QuerySet.update() briefly mentions that the model’s save() method is not called and pre_save/post_save signals are not sent. However, the docs do not explain why this matters or what those signals normally do. This could be confusing for new contributors who are understanding the difference between update(), and manually calling save() on each object. The current documentation could be updated to include information on why selecting the wrong method could disrupt current logic, or when it is safe/unsafe to use update().
Attachments (1)
Change History (10)
by , 4 weeks ago
| Attachment: | Screenshot 2025-11-17 at 11.05.58 PM.png added |
|---|
comment:1 by , 4 weeks ago
| Cc: | added |
|---|
comment:2 by , 4 weeks ago
| Needs documentation: | set |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
comment:3 by , 4 weeks ago
Additionally, the QuerySet.update() documentation's final paragraph provides more detailed explanation about signals:
(https://docs.djangoproject.com/en/5.2/ref/models/querysets/#update)
Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save()). If you want to update a bunch of records for a model that has a custom save() method, loop over them and call save(), like this:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
What are your thoughts on this explanation?
comment:4 by , 4 weeks ago
| Needs documentation: | unset |
|---|
comment:5 by , 4 weeks ago
| Summary: | Explain why pre_save/post_save signals are skipped when using QuerySet.update() → Link to discussion about Model.save() not being bulk-friendly from bulk_update() caveats |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
Thanks for the ticket.
I would take a PR that linked to the discussion about overriding the model save() method, which finishes with an admonition about it being not bulk-friendly. (Even better if we could link directly to that admonition, haven't tried doing so in Sphinx.)
comment:7 by , 3 weeks ago
| Patch needs improvement: | set |
|---|
comment:8 by , 3 weeks ago
| Patch needs improvement: | unset |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
(Note: The screenshot you attached is from the bulk_update() section, not the update() section. "QuerySet.update()" is linked and directs to the update() section.)
That said, I can see how the current wording could cause confusion - the bulk_update() documentation doesn't clarify that it uses update() internally.
I think the documentation could be improved with the following change:
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -2508,7 +2508,7 @@ >>> Entry.objects.bulk_update(objs, ["headline"]) 2 -:meth:`.QuerySet.update` is used to save the changes, so this is more efficient +This method uses :meth:`.QuerySet.update` internally, making it more efficient than iterating through the list of models and calling ``save()`` on each of them, but it has a few caveats: