mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
This change ensures that behavior and performance remain consistent when traversing relationships.
144 lines
4.3 KiB
Plaintext
144 lines
4.3 KiB
Plaintext
===========
|
|
Fetch modes
|
|
===========
|
|
|
|
.. versionadded:: 6.1
|
|
|
|
.. module:: django.db.models.fetch_modes
|
|
|
|
.. currentmodule:: django.db.models
|
|
|
|
When accessing model fields that were not loaded as part of the original query,
|
|
Django will fetch that field's data from the database. You can customize the
|
|
behavior of this fetching with a **fetch mode**, making it more efficient or
|
|
even blocking it.
|
|
|
|
Use :meth:`.QuerySet.fetch_mode` to set the fetch mode for model
|
|
instances fetched by a ``QuerySet``:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
|
|
books = Book.objects.fetch_mode(models.FETCH_PEERS)
|
|
|
|
Fetch modes apply to:
|
|
|
|
* :class:`~django.db.models.ForeignKey` fields
|
|
* :class:`~django.db.models.OneToOneField` fields and their reverse accessors
|
|
* Fields deferred with :meth:`.QuerySet.defer` or :meth:`.QuerySet.only`
|
|
* :ref:`generic-relations`
|
|
|
|
Django copies the fetch mode of an instance to any related objects it fetches,
|
|
so the mode applies to a whole tree of relationships, not just the top-level
|
|
model in the initial ``QuerySet``. This copying is also done in related
|
|
managers, even though fetch modes don't affect such managers' queries.
|
|
|
|
Available modes
|
|
===============
|
|
|
|
.. admonition:: Referencing fetch modes
|
|
|
|
Fetch modes are defined in ``django.db.models.fetch_modes``, but for
|
|
convenience they're imported into :mod:`django.db.models`. The standard
|
|
convention is to use ``from django.db import models`` and refer to the
|
|
fetch modes as ``models.<mode>``.
|
|
|
|
Django provides three fetch modes. We'll explain them below using these models:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
|
|
|
|
class Author(models.Model): ...
|
|
|
|
|
|
class Book(models.Model):
|
|
author = models.ForeignKey(Author, on_delete=models.CASCADE)
|
|
...
|
|
|
|
…and this loop:
|
|
|
|
.. code-block:: python
|
|
|
|
for book in books:
|
|
print(book.author.name)
|
|
|
|
…where ``books`` is a ``QuerySet`` of ``Book`` instances using some fetch mode.
|
|
|
|
.. attribute:: FETCH_ONE
|
|
|
|
Fetches the missing field for the current instance only. This is the default
|
|
mode.
|
|
|
|
Using ``FETCH_ONE`` for the above example would use:
|
|
|
|
* 1 query to fetch ``books``
|
|
* N queries, where N is the number of books, to fetch the missing ``author``
|
|
field
|
|
|
|
…for a total of 1+N queries. This query pattern is known as the "N+1 queries
|
|
problem" because it often leads to performance issues when N is large.
|
|
|
|
.. attribute:: FETCH_PEERS
|
|
|
|
Fetches the missing field for the current instance and its "peers"—instances
|
|
that came from the same initial ``QuerySet``. The behavior of this mode is
|
|
based on the assumption that if you need a field for one instance, you probably
|
|
need it for all instances in the same batch, since you'll likely process them
|
|
all identically.
|
|
|
|
Using ``FETCH_PEERS`` for the above example would use:
|
|
|
|
* 1 query to fetch ``books``
|
|
* 1 query to fetch all missing ``author`` fields for the batch of books
|
|
|
|
…for a total of 2 queries. The batch query makes this mode a lot more efficient
|
|
than ``FETCH_ONE`` and is similar to an on-demand call to
|
|
:meth:`.QuerySet.prefetch_related` or
|
|
:func:`~django.db.models.prefetch_related_objects`. Using ``FETCH_PEERS`` can
|
|
reduce most cases of the "N+1 queries problem" to two queries without
|
|
much effort.
|
|
|
|
The "peer" instances are tracked in a list of weak references, to avoid
|
|
memory leaks where some peer instances are discarded.
|
|
|
|
.. attribute:: RAISE
|
|
|
|
Raises a :exc:`~django.core.exceptions.FieldFetchBlocked` exception.
|
|
|
|
Using ``RAISE`` for the above example would raise an exception at the access of
|
|
``book.author`` access, like:
|
|
|
|
.. code-block:: python
|
|
|
|
FieldFetchBlocked("Fetching of Primary.value blocked.")
|
|
|
|
This mode can prevent unintentional queries in performance-critical
|
|
sections of code.
|
|
|
|
.. _fetch-modes-custom-manager:
|
|
|
|
Make a fetch mode the default for a model class
|
|
===============================================
|
|
|
|
Set the default fetch mode for a model class with a
|
|
:ref:`custom manager <custom-managers>` that overrides ``get_queryset()``:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
|
|
|
|
class BookManager(models.Manager):
|
|
def get_queryset(self):
|
|
return super().get_queryset().fetch_mode(models.FETCH_PEERS)
|
|
|
|
|
|
class Book(models.Model):
|
|
title = models.TextField()
|
|
author = models.ForeignKey("Author", on_delete=models.CASCADE)
|
|
|
|
objects = BookManager()
|