379 lines
15 KiB
Plaintext
379 lines
15 KiB
Plaintext
.. _topics-db-managers:
|
|
|
|
========
|
|
Managers
|
|
========
|
|
|
|
.. currentmodule:: django.db.models
|
|
|
|
.. class:: Manager()
|
|
|
|
A ``Manager`` is the interface through which database query operations are
|
|
provided to Django models. At least one ``Manager`` exists for every model in
|
|
a Django application.
|
|
|
|
The way ``Manager`` classes work is documented in :ref:`topics-db-queries`;
|
|
this document specifically touches on model options that customize ``Manager``
|
|
behavior.
|
|
|
|
.. _manager-names:
|
|
|
|
Manager names
|
|
=============
|
|
|
|
By default, Django adds a ``Manager`` with the name ``objects`` to every Django
|
|
model class. However, if you want to use ``objects`` as a field name, or if you
|
|
want to use a name other than ``objects`` for the ``Manager``, you can rename
|
|
it on a per-model basis. To rename the ``Manager`` for a given class, define a
|
|
class attribute of type ``models.Manager()`` on that model. For example::
|
|
|
|
from django.db import models
|
|
|
|
class Person(models.Model):
|
|
#...
|
|
people = models.Manager()
|
|
|
|
Using this example model, ``Person.objects`` will generate an
|
|
``AttributeError`` exception, but ``Person.people.all()`` will provide a list
|
|
of all ``Person`` objects.
|
|
|
|
.. _custom-managers:
|
|
|
|
Custom Managers
|
|
===============
|
|
|
|
You can use a custom ``Manager`` in a particular model by extending the base
|
|
``Manager`` class and instantiating your custom ``Manager`` in your model.
|
|
|
|
There are two reasons you might want to customize a ``Manager``: to add extra
|
|
``Manager`` methods, and/or to modify the initial ``QuerySet`` the ``Manager``
|
|
returns.
|
|
|
|
Adding extra Manager methods
|
|
----------------------------
|
|
|
|
Adding extra ``Manager`` methods is the preferred way to add "table-level"
|
|
functionality to your models. (For "row-level" functionality -- i.e., functions
|
|
that act on a single instance of a model object -- use :ref:`Model methods
|
|
<model-methods>`, not custom ``Manager`` methods.)
|
|
|
|
A custom ``Manager`` method can return anything you want. It doesn't have to
|
|
return a ``QuerySet``.
|
|
|
|
For example, this custom ``Manager`` offers a method ``with_counts()``, which
|
|
returns a list of all ``OpinionPoll`` objects, each with an extra
|
|
``num_responses`` attribute that is the result of an aggregate query::
|
|
|
|
class PollManager(models.Manager):
|
|
def with_counts(self):
|
|
from django.db import connection
|
|
cursor = connection.cursor()
|
|
cursor.execute("""
|
|
SELECT p.id, p.question, p.poll_date, COUNT(*)
|
|
FROM polls_opinionpoll p, polls_response r
|
|
WHERE p.id = r.poll_id
|
|
GROUP BY 1, 2, 3
|
|
ORDER BY 3 DESC""")
|
|
result_list = []
|
|
for row in cursor.fetchall():
|
|
p = self.model(id=row[0], question=row[1], poll_date=row[2])
|
|
p.num_responses = row[3]
|
|
result_list.append(p)
|
|
return result_list
|
|
|
|
class OpinionPoll(models.Model):
|
|
question = models.CharField(max_length=200)
|
|
poll_date = models.DateField()
|
|
objects = PollManager()
|
|
|
|
class Response(models.Model):
|
|
poll = models.ForeignKey(Poll)
|
|
person_name = models.CharField(max_length=50)
|
|
response = models.TextField()
|
|
|
|
With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return
|
|
that list of ``OpinionPoll`` objects with ``num_responses`` attributes.
|
|
|
|
Another thing to note about this example is that ``Manager`` methods can
|
|
access ``self.model`` to get the model class to which they're attached.
|
|
|
|
Modifying initial Manager QuerySets
|
|
-----------------------------------
|
|
|
|
A ``Manager``'s base ``QuerySet`` returns all objects in the system. For
|
|
example, using this model::
|
|
|
|
class Book(models.Model):
|
|
title = models.CharField(max_length=100)
|
|
author = models.CharField(max_length=50)
|
|
|
|
...the statement ``Book.objects.all()`` will return all books in the database.
|
|
|
|
You can override a ``Manager``\'s base ``QuerySet`` by overriding the
|
|
``Manager.get_query_set()`` method. ``get_query_set()`` should return a
|
|
``QuerySet`` with the properties you require.
|
|
|
|
For example, the following model has *two* ``Manager``\s -- one that returns
|
|
all objects, and one that returns only the books by Roald Dahl::
|
|
|
|
# First, define the Manager subclass.
|
|
class DahlBookManager(models.Manager):
|
|
def get_query_set(self):
|
|
return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl')
|
|
|
|
# Then hook it into the Book model explicitly.
|
|
class Book(models.Model):
|
|
title = models.CharField(max_length=100)
|
|
author = models.CharField(max_length=50)
|
|
|
|
objects = models.Manager() # The default manager.
|
|
dahl_objects = DahlBookManager() # The Dahl-specific manager.
|
|
|
|
With this sample model, ``Book.objects.all()`` will return all books in the
|
|
database, but ``Book.dahl_objects.all()`` will only return the ones written by
|
|
Roald Dahl.
|
|
|
|
Of course, because ``get_query_set()`` returns a ``QuerySet`` object, you can
|
|
use ``filter()``, ``exclude()`` and all the other ``QuerySet`` methods on it.
|
|
So these statements are all legal::
|
|
|
|
Book.dahl_objects.all()
|
|
Book.dahl_objects.filter(title='Matilda')
|
|
Book.dahl_objects.count()
|
|
|
|
This example also pointed out another interesting technique: using multiple
|
|
managers on the same model. You can attach as many ``Manager()`` instances to
|
|
a model as you'd like. This is an easy way to define common "filters" for your
|
|
models.
|
|
|
|
For example::
|
|
|
|
class MaleManager(models.Manager):
|
|
def get_query_set(self):
|
|
return super(MaleManager, self).get_query_set().filter(sex='M')
|
|
|
|
class FemaleManager(models.Manager):
|
|
def get_query_set(self):
|
|
return super(FemaleManager, self).get_query_set().filter(sex='F')
|
|
|
|
class Person(models.Model):
|
|
first_name = models.CharField(max_length=50)
|
|
last_name = models.CharField(max_length=50)
|
|
sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
|
|
people = models.Manager()
|
|
men = MaleManager()
|
|
women = FemaleManager()
|
|
|
|
This example allows you to request ``Person.men.all()``, ``Person.women.all()``,
|
|
and ``Person.people.all()``, yielding predictable results.
|
|
|
|
If you use custom ``Manager`` objects, take note that the first
|
|
``Manager`` Django encounters (in the order in which they're defined
|
|
in the model) has a special status. Django interprets this first
|
|
``Manager`` defined in a class as the "default" ``Manager``, and
|
|
several parts of Django (though not the admin application) will use
|
|
that ``Manager`` exclusively for that model. As a result, it's often a
|
|
good idea to be careful in your choice of default manager, in order to
|
|
avoid a situation where overriding of ``get_query_set()`` results in
|
|
an inability to retrieve objects you'd like to work with.
|
|
|
|
.. _managers-for-related-objects:
|
|
|
|
Using managers for related object access
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
By default, Django uses an instance of a "plain" manager class when accessing
|
|
related objects (i.e. ``choice.poll``), not the default manager on the related
|
|
object. This is because Django needs to be able to retrieve the related
|
|
object, even if it would otherwise be filtered out (and hence be inaccessible)
|
|
by the default manager.
|
|
|
|
If the normal plain manager class (:class:`django.db.models.Manager`) is not
|
|
appropriate for your circumstances, you can force Django to use the same class
|
|
as the default manager for your model by setting the `use_for_related_fields`
|
|
attribute on the manager class. This is documented fully below_.
|
|
|
|
.. _below: manager-types_
|
|
|
|
.. _custom-managers-and-inheritance:
|
|
|
|
Custom managers and model inheritance
|
|
-------------------------------------
|
|
|
|
Class inheritance and model managers aren't quite a perfect match for each
|
|
other. Managers are often specific to the classes they are defined on and
|
|
inheriting them in subclasses isn't necessarily a good idea. Also, because the
|
|
first manager declared is the *default manager*, it is important to allow that
|
|
to be controlled. So here's how Django handles custom managers and
|
|
:ref:`model inheritance <model-inheritance>`:
|
|
|
|
1. Managers defined on non-abstract base classes are *not* inherited by
|
|
child classes. If you want to reuse a manager from a non-abstract base,
|
|
redeclare it explicitly on the child class. These sorts of managers are
|
|
likely to be fairly specific to the class they are defined on, so
|
|
inheriting them can often lead to unexpected results (particularly as
|
|
far as the default manager goes). Therefore, they aren't passed onto
|
|
child classes.
|
|
|
|
2. Managers from abstract base classes are always inherited by the child
|
|
class, using Python's normal name resolution order (names on the child
|
|
class override all others; then come names on the first parent class,
|
|
and so on). Abstract base classes are designed to capture information
|
|
and behavior that is common to their child classes. Defining common
|
|
managers is an appropriate part of this common information.
|
|
|
|
3. The default manager on a class is either the first manager declared on
|
|
the class, if that exists, or the default manager of the first abstract
|
|
base class in the parent hierarchy, if that exists. If no default
|
|
manager is explicitly declared, Django's normal default manager is
|
|
used.
|
|
|
|
These rules provide the necessary flexibility if you want to install a
|
|
collection of custom managers on a group of models, via an abstract base
|
|
class, but still customize the default manager. For example, suppose you have
|
|
this base class::
|
|
|
|
class AbstractBase(models.Model):
|
|
...
|
|
objects = CustomManager()
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
If you use this directly in a subclass, ``objects`` will be the default
|
|
manager if you declare no managers in the base class::
|
|
|
|
class ChildA(AbstractBase):
|
|
...
|
|
# This class has CustomManager as the default manager.
|
|
|
|
If you want to inherit from ``AbstractBase``, but provide a different default
|
|
manager, you can provide the default manager on the child class::
|
|
|
|
class ChildB(AbstractBase):
|
|
...
|
|
# An explicit default manager.
|
|
default_manager = OtherManager()
|
|
|
|
Here, ``default_manager`` is the default. The ``objects`` manager is
|
|
still available, since it's inherited. It just isn't used as the default.
|
|
|
|
Finally for this example, suppose you want to add extra managers to the child
|
|
class, but still use the default from ``AbstractBase``. You can't add the new
|
|
manager directly in the child class, as that would override the default and you would
|
|
have to also explicitly include all the managers from the abstract base class.
|
|
The solution is to put the extra managers in another base class and introduce
|
|
it into the inheritance hierarchy *after* the defaults::
|
|
|
|
class ExtraManager(models.Model):
|
|
extra_manager = OtherManager()
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
class ChildC(AbstractBase, ExtraManager):
|
|
...
|
|
# Default manager is CustomManager, but OtherManager is
|
|
# also available via the "extra_manager" attribute.
|
|
|
|
.. _manager-types:
|
|
|
|
Controlling Automatic Manager Types
|
|
===================================
|
|
|
|
This document has already mentioned a couple of places where Django creates a
|
|
manager class for you: `default managers`_ and the "plain" manager used to
|
|
`access related objects`_. There are other places in the implementation of
|
|
Django where temporary plain managers are needed. Those automatically created
|
|
managers will normally be instances of the :class:`django.db.models.Manager`
|
|
class.
|
|
|
|
.. _default managers: manager-names_
|
|
.. _access related objects: managers-for-related-objects_
|
|
|
|
Throughout this section, we will use the term "automatic manager" to mean a
|
|
manager that Django creates for you -- either as a default manager on a model
|
|
with no managers, or to use temporarily when accessing related objects.
|
|
|
|
Sometimes this default class won't be the right choice. One example is in the
|
|
:mod:`django.contrib.gis` application that ships with Django itself. All ``gis``
|
|
models must use a special manager class (:class:`~django.contrib.gis.db.models.GeoManager`)
|
|
because they need a special queryset (:class:`~django.contrib.gis.db.models.GeoQuerySet`)
|
|
to be used for interacting with the database. It turns out that models which require
|
|
a special manager like this need to use the same manager class wherever an automatic
|
|
manager is created.
|
|
|
|
Django provides a way for custom manager developers to say that their manager
|
|
class should be used for automatic managers whenever it is the default manager
|
|
on a model. This is done by setting the ``use_for_related_fields`` attribute on
|
|
the manager class::
|
|
|
|
class MyManager(models.Manager):
|
|
use_for_related_fields = True
|
|
|
|
...
|
|
|
|
If this attribute is set on the *default* manager for a model (only the
|
|
default manager is considered in these situations), Django will use that class
|
|
whenever it needs to automatically create a manager for the class. Otherwise,
|
|
it will use :class:`django.db.models.Manager`.
|
|
|
|
.. admonition:: Historical Note
|
|
|
|
Given the purpose for which it's used, the name of this attribute
|
|
(``use_for_related_fields``) might seem a little odd. Originally, the
|
|
attribute only controlled the type of manager used for related field
|
|
access, which is where the name came from. As it became clear the concept
|
|
was more broadly useful, the name hasn't been changed. This is primarily
|
|
so that existing code will :ref:`continue to work <misc-api-stability>` in
|
|
future Django versions.
|
|
|
|
Writing Correct Managers For Use In Automatic Manager Instances
|
|
---------------------------------------------------------------
|
|
|
|
As already suggested by the `django.contrib.gis` example, above, the
|
|
``use_for_related_fields`` feature is primarily for managers that need to
|
|
return a custom ``QuerySet`` subclass. In providing this functionality in your
|
|
manager, there are a couple of things to remember.
|
|
|
|
Do not filter away any results in this type of manager subclass
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
One reason an automatic manager is used is to access objects that are related
|
|
to from some other model. In those situations, Django has to be able to see
|
|
all the objects for the model it is fetching, so that *anything* which is
|
|
referred to can be retrieved.
|
|
|
|
If you override the ``get_query_set()`` method and filter out any rows, Django
|
|
will return incorrect results. Don't do that. A manager that filters results
|
|
in ``get_query_set()`` is not appropriate for use as an automatic manager.
|
|
|
|
Set ``use_for_related_fields`` when you define the class
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ``use_for_related_fields`` attribute must be set on the manager *class*,
|
|
object not on an *instance* of the class. The earlier example shows the
|
|
correct way to set it, whereas the following will not work::
|
|
|
|
# BAD: Incorrect code
|
|
class MyManager(models.Manager):
|
|
...
|
|
|
|
# Sets the attribute on an instance of MyManager. Django will
|
|
# ignore this setting.
|
|
mgr = MyManager()
|
|
mgr.use_for_related_fields = True
|
|
|
|
class MyModel(models.Model):
|
|
...
|
|
objects = mgr
|
|
|
|
# End of incorrect code.
|
|
|
|
You also shouldn't change the attribute on the class object after it has been
|
|
used in a model, since the attribute's value is processed when the model class
|
|
is created and not subsequently reread. Set the attribute on the manager class
|
|
when it is first defined, as in the initial example of this section and
|
|
everything will work smoothly.
|
|
|