diff -r 5ff1fc726848 -r c6bca38c1cbf parts/django/docs/topics/db/managers.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parts/django/docs/topics/db/managers.txt Sat Jan 08 11:20:57 2011 +0530 @@ -0,0 +1,376 @@ +======== +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 :doc:`/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 +`, 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 the first ``Manager`` defined in a class as +the "default" ``Manager``, and several parts of Django +(including :djadmin:`dumpdata`) will use that ``Manager`` +exclusively for that model. As a result, it's a good idea to be careful in +your choice of default manager in order to avoid a situation where overriding +``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 `: + + 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 :doc:`continue to work ` 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. +