Skip to content

Commit

Permalink
Allow for disabling all queries in context manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-Chen-Wang committed Jul 29, 2020
1 parent 750b494 commit b68067f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
18 changes: 13 additions & 5 deletions cachalot/api.py
Expand Up @@ -134,25 +134,33 @@ def get_last_invalidation(*tables_or_models, **kwargs):


@contextmanager
def cachalot_disabled():
def cachalot_disabled(all_queries=False):
"""
Context manager for temporarily disabling cachalot.
If you evaluate the same queryset a second time,
like normally for Django querysets, this will access
the variable that saved it in-memory.
For example:
qs = Test.objects.filter(blah=blah)
with cachalot_disabled():
qs = Test.objects.filter(blah=blah)
# Does a single query to the db
list(qs) # Evaluates queryset
# Because the qs was evaluated, it's
# saved in memory. Does 0 queries.
list(qs)
# Does 1 query to the db
# saved in memory:
list(qs) # this does 0 queries.
# This does 1 query to the db
list(Test.objects.filter(blah=blah))
If you evaluate the queryset outside the context manager, any duplicate
query will use the cached result unless an object creation happens in between
the original and duplicate query.
:arg all_queries: Any query, including already evaluated queries, are re-evaluated.
:type all_queries: bool
"""
was_enabled = getattr(LOCAL_STORAGE, "cachalot_enabled", cachalot_settings.CACHALOT_ENABLED)
LOCAL_STORAGE.enabled = False
LOCAL_STORAGE.disable_on_all = all_queries
yield
LOCAL_STORAGE.enabled = was_enabled
34 changes: 32 additions & 2 deletions cachalot/tests/read.py
Expand Up @@ -863,14 +863,44 @@ def test_unmanaged_model(self):
self.assert_tables(qs, UnmanagedModel)
self.assert_query_cached(qs)

def test_cachalot_disabled_multiple_queries_ignoring_in_mem_cache(self):
"""
Test that when queries are given the `cachalot_disabled` context manager,
the queries will not be cached.
"""
with cachalot_disabled(True):
qs = Test.objects.all()
with self.assertNumQueries(1):
data1 = list(qs.all())
Test.objects.create(
name='test3', owner=self.user,
date='1789-07-14', datetime='1789-07-14T16:43:27',
permission=self.t1__permission)
with self.assertNumQueries(1):
data2 = list(qs.all())
self.assertNotEqual(data1, data2)

def test_query_cachalot_disabled_even_if_already_cached(self):
"""
Test that when a query is given the `cachalot_disabled` context manager,
the query will not be cached and a query will be performed even if the
data is already cached
the query outside of the context manager will be cached. Any duplicated
query will use the original query's cached result.
"""
qs = Test.objects.all()
self.assert_query_cached(qs)
with cachalot_disabled() and self.assertNumQueries(0):
list(qs.all())

def test_duplicate_query_execute_anyways(self):
"""After an object is created, a duplicate query should execute
rather than use the cached result.
"""
qs = Test.objects.all()
self.assert_query_cached(qs)
Test.objects.create(
name='test3', owner=self.user,
date='1789-07-14', datetime='1789-07-14T16:43:27',
permission=self.t1__permission)
with cachalot_disabled() and self.assertNumQueries(1):
list(qs.all())

Expand Down

0 comments on commit b68067f

Please sign in to comment.