123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- .. _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 :ref:`topics-db-queries`; this
- document specifically touches on model options that customize ``Manager``
- behavior.
- 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.
- Using managers for related object access
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- By default, Django uses a "bare" (i.e. default) manager when accessing related
- objects (i.e. ``choice.poll``). If this default isn't appropriate for your
- default manager, you can force Django to use a custom manager for related object
- attributes by giving it a ``use_for_related_fields`` property::
- class MyManager(models.Manager)::
- use_for_related_fields = True
- ...
-
- ...
- 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 behaviour 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.
|