Django gives you two ways to change rows in the database:
instance.save() — runs your model's save() method, fires pre_save / post_save signals, refreshes auto_now fields, and writes the whole row. Use it when you want the model's full lifecycle.Model.objects.filter(...).update(field=...) — emits a single SQL UPDATE and changes only the columns you name. It bypasses save(), signals, and auto_now.The choice isn't about speed. It's about whether you want that lifecycle to run. If your save() validates, normalises, or has side effects you don't want to repeat for a small state change, use .update().
In this repo, UserFeed.save() re-checks the URL and raises ValueError on bad input. When crawl_feed records "I just fetched this", it only wants to bump the scheduling fields. Re-checking the URL here would be wrong:
UserFeed.objects.filter(pk=feed.pk).update(
last_fetched_at=fetched_at,
next_check_at=fetched_at + HEALTHY_INTERVAL,
)
One trap: .update() does not touch auto_now fields. If you need updated_at to change, use .save() or set it yourself.
.save() you could replace with .update() — pick one in this repo where only one or two fields change and the model's save() lifecycle is irrelevant. Write down what you'd lose by switching (signals? auto_now?).
Done when: you have a one-paragraph note in this file describing the trade-off for that specific call site.auto_now=True on a field, then .update() a different field. Confirm the auto_now field is not refreshed.
Done when: you can explain why auto_now and .update() don't mix in one sentence.