diff options
| author | Loïc Bistuer <loic.bistuer@gmail.com> | 2016-04-17 18:55:55 +0700 |
|---|---|---|
| committer | Loïc Bistuer <loic.bistuer@gmail.com> | 2016-05-17 12:07:22 +0700 |
| commit | ed0ff913c648b16c4471fc9a9441d1ee48cb5420 (patch) | |
| tree | bf9cd3fad9f4c9abbec1967817842fdacad0938a /docs | |
| parent | 3a47d42fa33012b2156bf04058d933df6b3082d2 (diff) | |
Fixed #10506, #13793, #14891, #25201 -- Introduced new APIs to specify models' default and base managers.
This deprecates use_for_related_fields.
Old API:
class CustomManager(models.Model):
use_for_related_fields = True
class Model(models.Model):
custom_manager = CustomManager()
New API:
class Model(models.Model):
custom_manager = CustomManager()
class Meta:
base_manager_name = 'custom_manager'
Refs #20932, #25897.
Thanks Carl Meyer for the guidance throughout this work.
Thanks Tim Graham for writing the docs.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/internals/deprecation.txt | 6 | ||||
| -rw-r--r-- | docs/ref/models/options.txt | 20 | ||||
| -rw-r--r-- | docs/releases/1.10.txt | 23 | ||||
| -rw-r--r-- | docs/topics/db/managers.txt | 172 |
4 files changed, 100 insertions, 121 deletions
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 218e79d66f..d4bde35a46 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -175,6 +175,12 @@ details on these changes. * The ``escape`` filter will change to use ``django.utils.html.conditional_escape()``. +* ``Manager.use_for_related_fields`` will be removed. + +* Model ``Manager`` inheritance will follow MRO inheritance rules and the + ``Meta.manager_inheritance_from_future`` to opt-in to this behavior will be + removed. + .. _deprecation-removed-in-1.10: 1.10 diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index 677916bf5c..9c77899d09 100644 --- a/docs/ref/models/options.txt +++ b/docs/ref/models/options.txt @@ -35,6 +35,16 @@ Available ``Meta`` options or ``app_label.model_name`` you can use ``model._meta.label`` or ``model._meta.label_lower`` respectively. +``base_manager_name`` +--------------------- + +.. attribute:: Options.base_manager_name + +.. versionadded:: 1.10 + +The name of the manager to use for the model's +:attr:`~django.db.models.Model._base_manager`. + ``db_table`` ------------ @@ -95,6 +105,16 @@ Django quotes column and table names behind the scenes. setting, if set. If the backend doesn't support tablespaces, this option is ignored. +``default_manager_name`` +------------------------ + +.. attribute:: Options.default_manager_name + +.. versionadded:: 1.10 + +The name of the manager to use for the model's +:attr:`~django.db.models.Model._default_manager`. + ``default_related_name`` ------------------------ diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index fa5d3ff108..3fd6431462 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -432,6 +432,13 @@ Models * ``Model.__init__()`` now sets values of virtual fields from its keyword arguments. +* The new :attr:`Meta.base_manager_name + <django.db.models.Options.base_manager_name>` and + :attr:`Meta.default_manager_name + <django.db.models.Options.default_manager_name>` options allow controlling + the :attr:`~django.db.models.Model._base_manager` and + :attr:`~django.db.models.Model._default_manager`, respectively. + Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ @@ -1063,6 +1070,22 @@ always be applied as the last filter no matter where in the filter chain it appeared) is deprecated. The filter will change to immediately apply :func:`~django.utils.html.conditional_escape` in Django 2.0. +``Manager.use_for_related_fields`` and inheritance changes +---------------------------------------------------------- + +``Manager.use_for_related_fields`` is deprecated in favor of setting +:attr:`Meta.base_manager_name <django.db.models.Options.base_manager_name>` on +the model. + +Model ``Manager`` inheritance will follow MRO inheritance rules in Django 2.0, +changing the current behavior where managers defined on non-abstract base +classes aren't inherited by child classes. A deprecating warning with +instructions on how to adapt your code is raised if you have any affected +managers. You'll either redeclare a manager from an abstract model on the child +class to override the manager from the concrete model, or you'll set the +model's ``Meta.manager_inheritance_from_future=True`` option to opt-in to the +new inheritance behavior. + Miscellaneous ------------- diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index 80598f0c98..74c93a0edc 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -172,35 +172,59 @@ and ``Person.people.all()``, yielding predictable results. .. _default-managers: Default managers -~~~~~~~~~~~~~~~~ +---------------- + +.. attribute:: Model._default_manager 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_queryset()`` results in an inability to retrieve objects you'd like to -work with. +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_queryset()`` results in an +inability to retrieve objects you'd like to work with. + +You can specify a custom default manager using :attr:`Meta.base_manager_name +<django.db.models.Options.base_manager_name>`. + +If you're writing some code that must handle an unknown model, for example, in +a third-party app that implements a generic view, use this manager (or +:attr:`~Model._base_manager`) rather than assuming the model has an ``objects`` +manager. + +Base managers +------------- + +.. attribute:: Model._base_manager .. _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. +By default, Django uses an instance of the ``Model._base_manager`` 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_. +If the normal base manager class (:class:`django.db.models.Manager`) isn't +appropriate for your circumstances, you can tell Django which class to use by +setting :attr:`Meta.base_manager_name +<django.db.models.Options.base_manager_name>`. -.. _below: manager-types_ +Don't filter away any results in this type of manager subclass +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This manager is used 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_queryset()`` method and filter out any rows, Django +will return incorrect results. Don't do that. A manager that filters results +in ``get_queryset()`` is not appropriate for use as a default manager. .. _calling-custom-queryset-methods-from-manager: @@ -321,19 +345,21 @@ You may also store the generated class into a variable:: Custom managers and model inheritance ------------------------------------- -Here's how Django handles custom managers and -:ref:`model inheritance <model-inheritance>`: +Here's how Django handles custom managers and :ref:`model inheritance +<model-inheritance>`: -1. Managers from base classes are always inherited by the child class, +#. Managers from 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). -2. 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 parent class in - the parent hierarchy, if that exists. If no manager is explicitly declared, - Django automatically creates the `objects` manager and it becomes the default - manager. +#. If no managers are declared on a model and/or its parents, Django + automatically creates the ``objects`` manager. + +#. The default manager on a class is either the one chosen with + :attr:`Meta.default_manager_name + <django.db.models.Options.default_manager_name>`, or the first manager + declared on the model, or the default manager of the first parent model. .. versionchanged:: 1.10 @@ -428,99 +454,3 @@ However, if you're overriding ``__getattr__`` or some other private method of your ``Manager`` object that controls object state, you should ensure that you don't affect the ability of your ``Manager`` to be copied. - -.. _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. The default manager -may not have all the methods you need to work with your data. A custom manager -class of your own will allow you to create custom ``QuerySet`` objects to give -you the information you need. - -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 </misc/api-stability>` in - future Django versions. - -Writing correct managers for use in automatic manager instances ---------------------------------------------------------------- - -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_queryset()`` method and filter out any rows, Django -will return incorrect results. Don't do that. A manager that filters results -in ``get_queryset()`` 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*, 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): - # ... - pass - - # 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. |
