summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorLoïc Bistuer <loic.bistuer@gmail.com>2016-04-17 18:55:55 +0700
committerLoïc Bistuer <loic.bistuer@gmail.com>2016-05-17 12:07:22 +0700
commited0ff913c648b16c4471fc9a9441d1ee48cb5420 (patch)
treebf9cd3fad9f4c9abbec1967817842fdacad0938a /docs
parent3a47d42fa33012b2156bf04058d933df6b3082d2 (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.txt6
-rw-r--r--docs/ref/models/options.txt20
-rw-r--r--docs/releases/1.10.txt23
-rw-r--r--docs/topics/db/managers.txt172
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.