From 8a642b88c31787fde612ba72d4b282e1c2444035 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 11 Aug 2020 17:40:12 +0100 Subject: [PATCH] Changed "Don't overuse count() or exists()" example to Python. --- docs/topics/db/optimization.txt | 54 ++++++++++++++------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/docs/topics/db/optimization.txt b/docs/topics/db/optimization.txt index e98d1c1e28..69eb58212a 100644 --- a/docs/topics/db/optimization.txt +++ b/docs/topics/db/optimization.txt @@ -260,47 +260,39 @@ Don't overuse ``count()`` and ``exists()`` If you are going to need other data from the QuerySet, evaluate it immediately. -For example, assuming an Email model that has a ``body`` attribute and a -many-to-many relation to User, the following template code is optimal: - -.. code-block:: html+django - - {% if display_inbox %} - {% with emails=user.emails.all %} - {% if emails %} -

You have {{ emails|length }} email(s)

- {% for email in emails %} -

{{ email.body }}

- {% endfor %} - {% else %} -

No messages today.

- {% endif %} - {% endwith %} - {% endif %} +For example, assuming an Email model that has a ``subject`` attribute and a +many-to-many relation to User, the following code is optimal:: + if display_emails: + emails = user.emails.all() + if emails: + print('You have', len(emails), 'emails:') + for email in emails: + print(email.subject) + else: + print('You do not have any emails.') It is optimal because: -#. Since QuerySets are lazy, this does no database queries if 'display_inbox' - is False. +#. Since QuerySets are lazy, this does no database queries if + ``display_emails`` is ``False``. -#. Use of :ttag:`with` means that we store ``user.emails.all`` in a variable - for later use, allowing its cache to be re-used. +#. Storing ``user.emails.all()`` in the ``emails`` variable allows its result + cache to be re-used. -#. The line ``{% if emails %}`` causes ``QuerySet.__bool__()`` to be called, - which causes the ``user.emails.all()`` query to be run on the database, and - at the least the first line to be turned into an ORM object. If there aren't - any results, it will return False, otherwise True. +#. The line ``if emails`` causes ``QuerySet.__bool__()`` to be called, which + causes the ``user.emails.all()`` query to be run on the database. If there + aren't any results, it will return ``False``, otherwise ``True``. -#. The use of ``{{ emails|length }}`` calls ``QuerySet.__len__()``, filling - out the rest of the cache without doing another query. +#. The use of ``len(emails)`` calls ``QuerySet.__len__()``, reusing the result + cache. -#. The :ttag:`for` loop iterates over the already filled cache. +#. The ``for`` loop iterates over the already filled cache. In total, this code does either one or zero database queries. The only -deliberate optimization performed is the use of the :ttag:`with` tag. Using -``QuerySet.exists()`` or ``QuerySet.count()`` at any point would cause -additional queries. +deliberate optimization performed is using the ``emails`` variable. Using +``QuerySet.exists()`` for the ``if`` or ``QuerySet.count()`` for the count +would each cause additional queries. Use ``QuerySet.update()`` and ``delete()`` ------------------------------------------