Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a setting for enabling iterator caching #263

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cachalot/monkey_patch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
import types
from collections.abc import Iterable
from functools import wraps
from time import time
Expand Down Expand Up @@ -62,6 +63,10 @@ def _get_result_or_execute_query(execute_query_func, cache,
pass

result = execute_query_func()

if result.__class__ == types.GeneratorType and not cachalot_settings.CACHALOT_CACHE_ITERATORS:
return result

if result.__class__ not in ITERABLES and isinstance(result, Iterable):
result = list(result)

Expand Down
1 change: 1 addition & 0 deletions cachalot/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Settings(object):
CACHALOT_DATABASES = 'supported_only'
CACHALOT_TIMEOUT = None
CACHALOT_CACHE_RANDOM = False
CACHALOT_CACHE_ITERATORS = False
CACHALOT_INVALIDATE_RAW = True
CACHALOT_ONLY_CACHABLE_TABLES = ()
CACHALOT_ONLY_CACHABLE_APPS = ()
Expand Down
11 changes: 9 additions & 2 deletions cachalot/tests/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,20 @@ def test_distinct(self):
self.assert_query_cached(qs, [self.t1])

def test_iterator(self):
with self.assertNumQueries(1):
with self.assertNumQueries(2):
data1 = list(Test.objects.iterator())
with self.assertNumQueries(0):
Comment on lines -247 to -249
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove these assertions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I did. Since I defaulted the setting to False this should run 2 queries. The below block now does what this block did before.

data2 = list(Test.objects.iterator())
self.assertListEqual(data2, data1)
self.assertListEqual(data2, [self.t1, self.t2])

with self.settings(CACHALOT_CACHE_ITERATORS=True):
with self.assertNumQueries(1):
data1 = list(Test.objects.iterator())
with self.assertNumQueries(0):
data2 = list(Test.objects.iterator())
self.assertListEqual(data2, data1)
self.assertListEqual(data2, [self.t1, self.t2])

def test_in_bulk(self):
with self.assertNumQueries(1):
data1 = Test.objects.in_bulk((5432, self.t2.pk, 9200))
Expand Down
14 changes: 14 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ Settings
:Description: If set to ``True``, caches random queries
(those with ``order_by('?')``).

``CACHALOT_CACHE_ITERATORS``
~~~~~~~~~~~~~~~~~~~~~~~~~

:Default: ``False``
:Description:
If set to ``True``, cache results from QuerySets that return
generators. This is useful for caching the result sets of QuerySets that
use ``.iterator()``.

.. warnings::
``.iterator()`` is often used for large result sets. Caching these can use large
amounts of local memory because django-cachalot has to first convert them to a list to
store them in the cache.

.. _CACHALOT_INVALIDATE_RAW:

``CACHALOT_INVALIDATE_RAW``
Expand Down
Loading