Skip to content

Commit

Permalink
Add a setting for enabling iterator caching
Browse files Browse the repository at this point in the history
  • Loading branch information
danlamanna committed Sep 3, 2024
1 parent 0a62691 commit 86948d3
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 2 deletions.
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):
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 responses 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

0 comments on commit 86948d3

Please sign in to comment.