mirror of https://github.com/django/django.git
[3.2.x] Changed "Don't overuse count() or exists()" example to Python.
Backport of 8a642b88c3
from master
This commit is contained in:
parent
73e7bfc8f5
commit
ba71cf38ea
|
@ -260,47 +260,39 @@ Don't overuse ``count()`` and ``exists()``
|
||||||
|
|
||||||
If you are going to need other data from the QuerySet, evaluate it immediately.
|
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
|
For example, assuming an Email model that has a ``subject`` attribute and a
|
||||||
many-to-many relation to User, the following template code is optimal:
|
many-to-many relation to User, the following code is optimal::
|
||||||
|
|
||||||
.. code-block:: html+django
|
|
||||||
|
|
||||||
{% if display_inbox %}
|
|
||||||
{% with emails=user.emails.all %}
|
|
||||||
{% if emails %}
|
|
||||||
<p>You have {{ emails|length }} email(s)</p>
|
|
||||||
{% for email in emails %}
|
|
||||||
<p>{{ email.body }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<p>No messages today.</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
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:
|
It is optimal because:
|
||||||
|
|
||||||
#. Since QuerySets are lazy, this does no database queries if 'display_inbox'
|
#. Since QuerySets are lazy, this does no database queries if
|
||||||
is False.
|
``display_emails`` is ``False``.
|
||||||
|
|
||||||
#. Use of :ttag:`with` means that we store ``user.emails.all`` in a variable
|
#. Storing ``user.emails.all()`` in the ``emails`` variable allows its result
|
||||||
for later use, allowing its cache to be re-used.
|
cache to be re-used.
|
||||||
|
|
||||||
#. The line ``{% if emails %}`` causes ``QuerySet.__bool__()`` to be called,
|
#. The line ``if emails`` causes ``QuerySet.__bool__()`` to be called, which
|
||||||
which causes the ``user.emails.all()`` query to be run on the database, and
|
causes the ``user.emails.all()`` query to be run on the database. If there
|
||||||
at the least the first line to be turned into an ORM object. If there aren't
|
aren't any results, it will return ``False``, otherwise ``True``.
|
||||||
any results, it will return False, otherwise True.
|
|
||||||
|
|
||||||
#. The use of ``{{ emails|length }}`` calls ``QuerySet.__len__()``, filling
|
#. The use of ``len(emails)`` calls ``QuerySet.__len__()``, reusing the result
|
||||||
out the rest of the cache without doing another query.
|
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
|
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
|
deliberate optimization performed is using the ``emails`` variable. Using
|
||||||
``QuerySet.exists()`` or ``QuerySet.count()`` at any point would cause
|
``QuerySet.exists()`` for the ``if`` or ``QuerySet.count()`` for the count
|
||||||
additional queries.
|
would each cause additional queries.
|
||||||
|
|
||||||
Use ``QuerySet.update()`` and ``delete()``
|
Use ``QuerySet.update()`` and ``delete()``
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue