Yes it’s another iteration of that question, but maybe I can settle the underlying conceptual issue instead of just re-asking “when to use a custom Manager vs QuerySet?”
Why didn’t the Django designers just make object
a QuerySet?
In general nobody can answer[^1] when not to use QuerySet.as_manager()
, or at least not beyond personal preference or convention[^2]. It’s been speculated[^3] that the distinction is just a hangover which has yet to be deprecated.
The closest I’ve found to functionality implied to exist for Managers but not QuerySets is that multiple models can have the same custom manager[^4]. But the article then contradicts this with an example custom queryset which, of course, is equally agnostic as to the model! Everything else in the article is pure convention: “Ideal for encapsulating methods affecting the entire queryset” vs “Designed for fine-grained, query-specific methods”? How? Why can’t querysets do the former? They have the same functionality under the same method names!
So much so in fact, that we have the infamous QuerySet.as_manager()
to preserve DRY[^5]…
EXCEPT reading that documentation we see
Not every
QuerySet
method makes sense at theManager
level; for instance we intentionally prevent theQuerySet.delete()
method from being copied onto theManager
class.Methods are copied according to the following rules:
- Public methods are copied by default.
- Private methods (starting with an underscore) are not copied by default.
- Methods with a
queryset_only
attribute set toFalse
are always copied.- Methods with a
queryset_only
attribute set toTrue
are never copied.
But those rules reveal nothing about the conceptual distinction that would cause a queryset method not to “make sense at the Manager level”.
A quick search of the Django codebase reveals queryset_only
is only used to prevent QuerySet.delete()
and QuerySet.as_manager()
itself from copying to the generated manager. But why doesn’t .delete()
“make sense at the Manager level”? Sure it’s unlikely you’d want to delete all records, but no less likely than wanting to do so on the queryset from Manager.all()
…
If this too never gets answered, then at least I’ve collated the confusion into one place, so future searchers needn’t feel they’re missing something obvious while scrolling through millions of “QuerySet vs Manager?” posts on here, Stack Overflow, Medium etc.
(Apologies for the footnotes, new forum users are only allowed 2 URLs per post)
[^1]https://forum.djangoproject.com/t/when-to-use-a-manager-instead-of-a-queryset-with-as-manager/29496
[^2]https://forum.djangoproject.com/t/model-methods-custom-managers-queryset-when-to-use-them/7028
[^3]https://forum.djangoproject.com/t/managers-adding-extra-manager-method-vs-creating-a-manager-with-queryset-methods/8876/4
[^4]https://medium.com/django-unleashed/when-and-how-to-override-managers-and-querysets-in-django-f9f8f228fcb4
[^5]https://docs.djangoproject.com/en/5.1/topics/db/managers/#creating-a-manager-with-queryset-methods