From 292f503845401868ae9bf02b9bb1c38f35774c2c Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Sun, 15 Mar 2009 03:42:08 +0000 Subject: [PATCH] Clarified and expanded documentation for Manager.use_for_related_fields. This is for Manager subclasses that are default managers, but only sometimes. The general rule is: "don't use it." If you really need it, read the instructions. git-svn-id: http://code.djangoproject.com/svn/django/trunk@10057 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/topics/db/managers.txt | 123 +++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index f7f0f25a32..102ff5036a 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -16,6 +16,8 @@ The way ``Manager`` classes work is documented :ref:`topics-db-queries`; this document specifically touches on model options that customize ``Manager`` behavior. +.. _manager-names: + Manager names ============= @@ -175,20 +177,23 @@ 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 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:: +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. - class MyManager(models.Manager):: - use_for_related_fields = True - ... - +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 model inheritance ------------------------------------- @@ -221,3 +226,103 @@ to be controlled. So here's how Django handles custom managers and manager is explicitly declared, Django's normal default manager is used. +.. _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 +`django.contrib.gis` application that ships with Django itself. All `gis` +models must use a special manager class (``GeoManager``) because they need a +special queryset (``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 ` 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 be remember and that's the topic of +this section. + +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. +