You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
8.8 KiB
223 lines
8.8 KiB
.. _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. |
|
|
|
|