8.9 Managers
A manager is the object a model class’s queries start from: Model.objects is one, an instance of django or of a subclass. A manager’s class gets its methods from a queryset class through BaseManager, a manager is read from its model through a ManagerDescriptor, and Django itself chooses between two of a model’s managers, the default manager and the base manager.
A queryset describes a query against one model, and each method that narrows it returns another queryset. Something has to supply the first one. That is the whole job of a manager: it knows its model, and when asked it makes a new queryset for it. A line such as this one is a manager making a queryset and passing the call on:
Ship.objects.filter(tonnage__gt=400)
Little is left for a manager to be. It holds a model, a name and a choice of database; BaseManager is where every query begins; and nearly every other method a manager seems to have is a few generated lines that call get_queryset and then the queryset’s method of the same name.
The crew’s models declare two managers, each written in a different way:
# harbour/crew/models.py
class SailorQuerySet(models.QuerySet):
def aboard(self, ship):
return self.filter(ship=ship)
class Sailor(models.Model):
# after its fields: name, ship, signed_on, pilots_into
objects = SailorQuerySet.as_manager()
class VeteranManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(signed_on__year__lt=2020)
class Veteran(Sailor):
objects = VeteranManager()
class Meta:
proxy = True
What a manager holds
BaseManager gives a new manager four attributes besides its creation counter: BaseManager and BaseManager.name, both None until the manager joins a class; an alias, None unless the manager has been told to use one database; and the hints it will pass to the database router, an empty dictionary. Two flags stand on the class: BaseManager, which is set on a manager Django added itself, and BaseManager.
A manager also takes a number. BaseManager is kept on the class, and each manager made takes its current value and moves it on, so that the managers of a model can be put in the order they were created in.
And it remembers how it was made. BaseManager stores the positional and keyword arguments of the call that constructed the manager, before __init__ runs, and the comment there says why: to make returning them trivial. BaseManager is what returns them, to a migration. BaseManager uses them too: it answers true when the other manager is an instance of this manager’s class and their stored arguments are equal.
Where the methods come from
django is declared with an empty body. All it has comes from its one base, and that base is written nowhere as a class statement: it is the value of an expression in Manager’s own, a call of BaseManager with QuerySet.
BaseManager makes a class by calling type. The class it was called on is the new class’s one base. Unless the caller gives a name, the name is that class’s name, the word From and the queryset class’s name run together, here BaseManagerFromQuerySet. The body is one attribute, "_queryset_class", holding the queryset class, and a method for each method of the queryset class that BaseManager picks out.
[c.__name__ for c in models.Manager.__mro__] -> ['Manager', 'BaseManagerFromQuerySet', 'BaseManager', 'object']
models.Manager.__mro__[1]._queryset_class -> <class 'django.db.models.query.QuerySet'>
'filter' in vars(models.Manager.__mro__[1]), 'filter' in vars(BaseManager), 'filter' in vars(models.Manager) -> (True, False, False)
models.Manager.filter.__qualname__ -> 'QuerySet.filter'
hasattr(models.Manager, 'delete'), hasattr(models.Manager, 'as_manager'), hasattr(models.Manager, '_insert'), hasattr(models.Manager, '_clone') -> (False, False, True, False)
models.QuerySet.delete.queryset_only, models.QuerySet._insert.queryset_only, models.QuerySet.as_manager.queryset_only -> (True, False, True)
_get_queryset_methods goes through every plain function that inspect finds on the queryset class, inherited ones included, and passes over one for any of three reasons.
The manager class already has an attribute of that name. This is why QuerySet.all is not copied: BaseManager has a method of that name already.
The function carries an attribute "queryset_only" that is true. QuerySet.delete and its asynchronous twin QuerySet.adelete are marked so, and QuerySet. QuerySet carries the mark too, but as a class method it is not one of the plain functions the loop is given. The source marks delete and gives no reason. Django’s documentation does: keeping it off the manager is a safety mechanism, so that a call on the manager alone cannot delete every row of a table.
Or it carries no such attribute and its name begins with an underscore. The mark settles the matter either way, so a private method marked false is copied all the same. QuerySet._insert and QuerySet._update are, and the insert of a save is a call of the first on a manager (Saving an instance).
What is copied is not the queryset’s function. For each name, a new function is made that takes the manager and any arguments, calls get_queryset, looks the name up on the queryset that comes back, and calls what it finds with the arguments. It is passed through functools.wraps, so it bears the queryset method’s name and docstring, and its qualified name, as the fourth line above shows. A call through it looks like this:
Sailor.objects.filter(name='Ada')
ManagerDescriptor.__get__(None, Sailor) -> a ManagerFromSailorQuerySet
manager_method (the method the manager's class was given under the name 'filter')
BaseManager.get_queryset (a ManagerFromSailorQuerySet) -> a SailorQuerySet of Sailor, not yet fetched
QuerySet.filter(name='Ada')
Two things follow. Every call through a manager begins with a new queryset, and a manager keeps nothing between one call and the next. And the method is found by name, at the moment of the call, on whatever get_queryset returned, so a manager that changes what get_queryset returns has changed all of its copied methods at once.
The methods are chosen when the manager’s class is made, which for Manager is when its module is first imported.
A queryset class of the project’s
BaseManager serves a project’s own queryset class in the same way. Given a subclass of QuerySet with methods of its own, it returns a manager class that has those methods beside the standard ones. QuerySet is the short way to it: a class method that calls from_queryset on Manager with the class it is itself called on, makes an instance of the result, sets "_built_with_as_manager" on the instance, and returns it. Sailor’s manager is made so. Its class is a generated one, with the other generated class further down among its bases:
[c.__name__ for c in type(Sailor.objects).__mro__] -> ['ManagerFromSailorQuerySet', 'Manager', 'BaseManagerFromQuerySet', 'BaseManager', 'object']
hasattr(Sailor.objects, 'aboard'), hasattr(Ship.objects, 'aboard') -> (True, False)
A method written once on the queryset class is then to be had in both places: on the manager, through the generated method, and on every queryset the manager makes, because get_queryset makes an object of "_queryset_class". The second is recorded here:
Sailor.objects.all().aboard(petrel)
ManagerDescriptor.__get__(None, Sailor) -> a ManagerFromSailorQuerySet
BaseManager.all
BaseManager.get_queryset (a ManagerFromSailorQuerySet) -> a SailorQuerySet of Sailor, not yet fetched
SailorQuerySet.aboard(<Ship: Petrel>)
QuerySet.filter(ship=<Ship: Petrel>)
-> a SailorQuerySet of Sailor, not yet fetched
get_queryset: where a manager narrows
BaseManager returns a new object of the manager’s queryset class, made with the manager’s model, its alias and its hints. Since every copied method starts there, overriding it is the way to give a manager a narrower idea of its model’s rows. VeteranManager does that, and nothing else:
Veteran.objects.all()
ManagerDescriptor.__get__(None, Veteran) -> a VeteranManager
BaseManager.all
VeteranManager.get_queryset
BaseManager.get_queryset (a VeteranManager) -> a QuerySet of Veteran, not yet fetched
QuerySet.filter(signed_on__year__lt=2020)
-> a QuerySet of Veteran, not yet fetched
The filter is then in every query that starts from one of the manager’s copied methods.
BaseManager.all is a queryset method that BaseManager writes out for itself, and it returns what get_queryset returns. The comment on it explains why it is not left to the generated kind. QuerySet.all works by copying the queryset it is called on, and the copy loses any results cached by prefetch_related; the get_queryset of a related manager may hand back just such a queryset of prefetched results, and the manager’s method must not throw them away.
EmptyManager overrides get_queryset as well. It is a Manager for a place where there is no table to ask: it is given its model in its constructor, without joining any class, and its get_queryset returns the queryset that QuerySet.none gives, which fetches nothing. AnonymousUser, which is not a model, has two of them, for its groups and for its permissions.
A manager joins a class
A manager in a class body is one of the attributes the metaclass holds back and then hands the class to (ModelBase: a class statement becomes a model). BaseManager takes the attribute’s name as the manager’s own, unless the manager has one already, and records the class as its model. It sets a ManagerDescriptor on the class under that name. And it enters the manager in the class’s options with Options, which appends it to Options and discards what the options had cached.
ModelBase.add_to_class(Sailor, 'objects', a ManagerFromSailorQuerySet)
BaseManager.contribute_to_class(Sailor, 'objects') (a ManagerFromSailorQuerySet)
ManagerDescriptor.__init__(a ManagerFromSailorQuerySet)
Options.add_manager(a ManagerFromSailorQuerySet)
A class that declares no manager, and inherits none, is given one. ModelBase asks the options for the class’s managers, and when there are none it makes a Manager, sets auto_created on it, and adds it under the name "objects" in the same way. This is Ship, with the part of the method that adds a primary key left out:
ModelBase._prepare(Ship)
ModelBase.add_to_class(Ship, 'objects', a Manager)
BaseManager.contribute_to_class(Ship, 'objects') (a Manager)
ManagerDescriptor.__init__(a Manager)
Options.add_manager(a Manager)
A model that has a field named "objects" and no manager cannot be given that one, and the method raises ValueError for it. An abstract class is never prepared, and so is given no automatic manager.
Reading it back: ManagerDescriptor
What stands on the class under the manager’s name is not the manager, and what comes back from reading it is not the manager the body declared either:
type(vars(Sailor)['objects']).__name__, Sailor.objects is Sailor.objects -> ('ManagerDescriptor', True)
Sailor._meta.local_managers[0] is Sailor.objects, Sailor._meta.local_managers[0] == Sailor.objects -> (False, True)
ManagerDescriptor refuses three kinds of read with AttributeError. A manager is not to be reached through an instance: it belongs to the class. It is not to be had from an abstract class, which may declare a manager for its children and cannot use it. And it is not to be had from a model that a setting has swapped for another (The user model: AbstractBaseUser, User and AUTH_USER_MODEL).
Ship(name='Heron').objects -> raises AttributeError: Manager isn't accessible via Ship instances
Named.objects -> raises AttributeError: type object 'Named' has no attribute 'objects'
The first line is the descriptor’s refusal. The second is not: Named declares no manager and was given none, so there is no descriptor and the error is Python’s own.
For any other read the descriptor returns one entry of a dictionary, Options, kept by the options of the class the attribute was read on: the entry under the name of the manager it was made for.
The managers of a class, and of its parents
Options.managers builds the list of a class’s managers the first time it is asked. It goes through the classes in the model’s method resolution order that have options, the model itself first, and takes each one’s local_managers. A manager whose name has already been taken by a class nearer the front is passed over. Of each of the others it makes a shallow copy and sets the copy’s model to the model that is asking. The copies are sorted by how far along the order their class stands, and within one class by creation counter. managers_map is the same list as a dictionary by name.
So even a class’s own manager is handed out as a copy. The object written in the body stays in local_managers as the pattern, which is why it and the manager read from Sailor were recorded as two objects, and equal ones: the copy carries the same constructor’s arguments. The copy is made once and kept for as long as the options keep their cached lists, so two reads give the same object. When the cache is discarded, as it is whenever a field or a manager is added to the class, the next read makes a new copy.
A child gets its parents’ managers by the same walk. Officer declares none and has no descriptor of its own. Python finds Sailor’s, the descriptor asks Officer’s options, and their walk reaches the manager in Sailor’s local_managers:
names(Sailor._meta.managers), names(Officer._meta.local_managers), names(Officer._meta.managers) -> ([objects], [], [objects])
Officer.objects.model, Officer.objects is Sailor.objects, type(Officer.objects) is type(Sailor.objects) -> (<class 'harbour.crew.models.Officer'>, False, True)
The walk does not ask what kind of base a class is. An abstract base’s managers are found by it, and so are those of the model behind a proxy (Inheritance: abstract bases, parents with tables and proxies).
And a manager is replaced by declaring another under its name. Veteran’s body has a manager called "objects", so Sailor’s is passed over for Veteran:
What the class Veteran holds in its own __dict__, in the order the names were set
__doc__: 'The sailors who signed on before 2020. A proxy: the same table, another class.'
_meta: an Options
DoesNotExist: the class Veteran.DoesNotExist
MultipleObjectsReturned: the class Veteran.MultipleObjectsReturned
NotUpdated: the class Veteran.NotUpdated
objects: a ManagerDescriptor
The replacement is whole. VeteranManager is built on Manager, so the querysets it makes are plain QuerySets, as was recorded where its get_queryset ran, and "aboard" is not among its methods.
The default manager and the base manager
Much of Django has to query a model without having been told which of its managers to use: to find the row a save should update, to follow a foreign key, to see whether a value is already taken. It cannot go by the name "objects", which a model need not have. Each model class therefore answers to two more names, ModelBase and ModelBase, properties declared on the metaclass, which makes them attributes of a model class and not of its instances. They return what the options work out as Options and Options.
Unless a model says otherwise, its default manager is the first of its managers, the project’s own where the project wrote one, and its base manager is a plain Manager whatever the project wrote:
type(Sailor._default_manager).__name__, type(Sailor._base_manager).__name__, Sailor._base_manager.name -> ('ManagerFromSailorQuerySet', 'Manager', '_base_manager')
type(Veteran._default_manager).__name__, type(Veteran._base_manager).__name__ -> ('VeteranManager', 'Manager')
The first of its managers is the first of Options.managers: the first manager the class itself created, or else the first of the nearest base that has any. A class with no manager at all, as an abstract one may be, has None for a default manager. The plain Manager is made on the spot and kept with the options’ other cached values, under the name "_base_manager" and with the class as its model. It never joins the class: it has no descriptor and is in none of the options’ lists.
A model says otherwise in its Meta, by naming one of its managers as "default_manager_name" or as "base_manager_name"; a name that is no manager of the class raises ValueError when that manager is asked for. A class that names no default manager and declares no manager of its own goes by the setting in its nearest model base’s options, if the Meta that base went by gave one. A class that names no base manager goes by the name of its nearest model base’s base manager, where that is a named manager and not the plain one, and takes its own manager of that name; a name given once therefore passes down the line to every class that names none.
Who asks which
django/db/models/ goes to, in the places this chapter passes through.| what Django is doing | the manager it asks | where |
|---|---|---|
| saving: the update and the insert of each table | the manager it asks base, of the class whose table it is | where Model django/ |
Model, and through it a deferred field read for one instance |
the manager it asks base, of the instance’s class | where Model django/ |
| a deferred field fetched for several instances together | the manager it asks base, of the model the field belongs to | where Deferred django/ |
| reading the object a foreign key or a one-to-one field points at | the manager it asks base, of the model pointed at | where Forward django/ |
| reading the object at the other end of a one-to-one field | the manager it asks base, of the model with the field | where Reverse django/ |
| validating that the value of a foreign key has a row | the manager it asks base, of the model pointed at | where Foreign django/ |
| finding the rows that point at an object being deleted | the manager it asks base, of the model those rows belong to | where Collector django/ |
adding objects through the manager at the other end of a foreign key, with bulk=True |
the manager it asks base, of the model with the foreign key | where create_ django/ |
the unique checks of Model.full_clean |
the manager it asks default, of the class the field belongs to, or whose options hold the unique_together |
where Model django/ |
validating a UniqueConstraint |
the manager it asks default, of the class whose options hold the constraint | where Unique django/ |
| the next or previous instance by a date field | the manager it asks default, of the instance’s class | where Model django/ |
| the choices a foreign key offers to a form | the manager it asks default, of the model pointed at | where Foreign django/ |
| adding and removing the rows of a many-to-many relation | the manager it asks default, of the through model | where create_ django/ |
| the manager at the other end of a foreign key | the manager it asks a subclass of the class of the default manager of the model with the foreign key | where Reverse django/ |
| the manager at either end of a many-to-many field | the manager it asks a subclass of the class of the default manager of the model at the other end | where Many django/ |
Django’s documentation gives a reason for the rows about a related object: it has to be retrievable even when the default manager would filter it out. For the same reason the documentation tells a project that names a base manager not to filter rows away in it.
The last two rows are of another kind. A related manager is an object of a class made at run time: a subclass of the class of the default manager of the model it gives access to, or of another of that model’s managers when it is asked for by that manager’s name. It has whatever methods that class has, beside its own, of which remove and clear are defined only where the foreign key can be null, as the one from Sailor to Ship cannot (Reading and setting related objects, Many-to-many relations):
[c.__name__ for c in type(petrel.crew).__mro__] -> ['RelatedManager', 'ManagerFromSailorQuerySet', 'Manager', 'BaseManagerFromQuerySet', 'BaseManager', 'AltersData', 'object']
hasattr(petrel.crew, 'aboard'), hasattr(petrel.crew, 'remove'), hasattr(petrel.crew, 'clear') -> (True, False, False)
A default manager that filters
The difference between the default manager and the base manager shows when a default manager’s get_queryset leaves rows out, as Veteran’s does. Bram signed on in 2026, so no queryset that starts from "objects" of Veteran will find him. The base manager of Veteran does, and the instance it gives is saved with an update of his row, here without two of the save’s calls:
Veteran.objects.filter(name='Bram').exists(), Veteran._base_manager.filter(name='Bram').exists() -> (False, True)
SQL SELECT %s AS "a" FROM "crew_sailor" WHERE ("crew_sailor"."signed_on" < %s AND "crew_sailor"."name" = %s) LIMIT 1 with params (1, '2020-01-01 00:00:00', 'Bram')
SQL SELECT %s AS "a" FROM "crew_sailor" WHERE "crew_sailor"."name" = %s LIMIT 1 with params (1, 'Bram')
hidden = Veteran._base_manager.get(name='Bram'), and hidden.save()
SQL SELECT "crew_sailor"."id", "crew_sailor"."name", "crew_sailor"."ship_id", "crew_sailor"."signed_on" FROM "crew_sailor" WHERE "crew_sailor"."name" = %s LIMIT 21 with params ('Bram',)
Model.save() (a Veteran)
Model.save_base()
Model._save_table(cls=Sailor)
Model._do_update(pk_val=2, values for [name, ship, signed_on])
SQL UPDATE "crew_sailor" SET "name" = %s, "ship_id" = %s, "signed_on" = %s WHERE "crew_sailor"."id" = %s with params ('Bram', 1, '2026-04-10 09:00:00', 2)
-> [()]
-> updated: True
A row the default manager hides can still be saved, refreshed and reached through a foreign key, because none of those asks the default manager. The save above does not ask a manager of Veteran at all: Model.save_base exchanges a proxy for its concrete model, and the update goes through the base manager of Sailor.
The related sets do follow the default manager. The get_queryset of a related manager starts from its base class’s, which is the default manager’s, and narrows the result to the one instance. A filter in the first is in a related set fetched that way, which leaves out one asked for by another manager’s name and one prefetched with a queryset of the caller’s own.
And validation follows it, with a consequence. The unique checks look for an existing row through the default manager of the class the field belongs to. A row that manager hides is not found, the check passes, and the database refuses the duplicate when it is saved (Validating an instance). Veteran is not such a case, its manager notwithstanding: Veteran has no fields of its own, every unique check on a Veteran belongs to Sailor, and it is Sailor’s default manager that is asked.
Another database: db_manager and the hints
BaseManager returns a shallow copy of the manager with an alias, or hints, or both, set on it. get_queryset passes both to the queryset it makes, and BaseManager.db answers with the alias, or without one with whatever ConnectionRouter says for the model and the hints.
The hints are keyword arguments for the database routers. ConnectionRouter passes them, with the model, to each router’s method in turn, and where none of them chooses it answers itself: with the database of the hint called "instance", if that object has one, and otherwise with the default. Model and the two descriptors that fetch one related object, ForwardManyToOneDescriptor and ReverseOneToOneDescriptor, make their querysets from db_manager with the instance as that hint.
A manager also has QuerySet.using, copied like the rest. That returns a queryset. db_manager returns a manager, and is the way to call, against another database, a method that the manager’s class defines and the queryset’s does not. The command that creates a superuser does so for a method of the user model’s manager, which on Django’s own user model is UserManager.
What a migration keeps of a manager
BaseManager describes a manager as five values from which it can be made again: whether it was made by as_manager, the dotted path of its class, the dotted path of its queryset class, and the positional and the keyword arguments it was constructed with. A migration that carries a manager writes it down and rebuilds it by them. A manager made by as_manager is described by the first and the third, the others being None, and rebuilt by calling as_manager on that class again:
Sailor.objects.deconstruct()[:3] -> (True, None, 'harbour.crew.models.SailorQuerySet')
Any other is described by the dotted path of its own class and the arguments __new__ stored. That requires the class to be importable under its name from its module. A class that from_queryset made, used directly, is not, and for one deconstruct raises ValueError with the advice to inherit from it.
Not every manager is carried. ModelState keeps a copy of each manager whose class sets use_in_migrations, and of the rest at most a plain Manager in place of the default manager and another in place of the base manager, each under the name of the manager it stands for. It carries none at all where the one manager kept would be such a stand-in for the default manager, called "objects" (Project state: ProjectState and its model states).