diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0467b15..1ce02a3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ What’s new in django-cachalot? - Drop support for Django 2.0-2.1 and Python 3.5 (#181) - Add support for Pymemcache for Django 3.2+ (#181) - Reverts #157 with proper fix. (#181) +- Add ``CACHALOT_ADDITIONAL_TABLES`` setting for unmanaged models (#183) 2.3.5 ----- diff --git a/cachalot/settings.py b/cachalot/settings.py index e1d6383..063acba 100644 --- a/cachalot/settings.py +++ b/cachalot/settings.py @@ -53,6 +53,7 @@ class Settings(object): CACHALOT_INVALIDATE_RAW = True CACHALOT_ONLY_CACHABLE_TABLES = () CACHALOT_UNCACHABLE_TABLES = ('django_migrations',) + CACHALOT_ADDITIONAL_TABLES = () CACHALOT_QUERY_KEYGEN = 'cachalot.utils.get_query_cache_key' CACHALOT_TABLE_KEYGEN = 'cachalot.utils.get_table_cache_key' @@ -112,6 +113,11 @@ def convert(value): return frozenset(value) +@Settings.add_converter('CACHALOT_ADDITIONAL_TABLES') +def convert(value): + return list(value) + + @Settings.add_converter('CACHALOT_QUERY_KEYGEN') def convert(value): return import_string(value) diff --git a/cachalot/tests/settings.py b/cachalot/tests/settings.py index 09d4503..3c370eb 100644 --- a/cachalot/tests/settings.py +++ b/cachalot/tests/settings.py @@ -11,7 +11,7 @@ from django.test.utils import override_settings from ..api import invalidate from ..settings import SUPPORTED_ONLY, SUPPORTED_DATABASE_ENGINES -from .models import Test, TestParent, TestChild +from .models import Test, TestParent, TestChild, UnmanagedModel from .test_utils import TestUtilsMixin @@ -172,6 +172,14 @@ class SettingsTestCase(TestUtilsMixin, TransactionTestCase): self.assert_query_cached(TestParent.objects.all()) self.assert_query_cached(User.objects.all(), after=1) + def test_uncachable_unmanaged_table(self): + qs = UnmanagedModel.objects.all() + with self.settings( + CACHALOT_UNCACHABLE_TABLES=("cachalot_unmanagedmodel",), + CACHALOT_ADDITIONAL_TABLES=("cachalot_unmanagedmodel",) + ): + self.assert_query_cached(qs, after=1) + def test_cache_compatibility(self): compatible_cache = { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', diff --git a/cachalot/utils.py b/cachalot/utils.py index 1d19e41..fe9cc0c 100644 --- a/cachalot/utils.py +++ b/cachalot/utils.py @@ -97,7 +97,25 @@ def get_table_cache_key(db_alias, table): def _get_tables_from_sql(connection, lowercased_sql): return {t for t in connection.introspection.django_table_names() - if t in lowercased_sql} + + cachalot_settings.CACHALOT_ADDITIONAL_TABLES if t in lowercased_sql} + + +def _find_rhs_lhs_subquery(side): + h_class = side.__class__ + if h_class is Query: + return side + elif h_class is QuerySet: + return side.query + elif h_class in (Subquery, Exists): # Subquery allows QuerySet & Query + try: + return side.query.query if side.query.__class__ is QuerySet else side.query + except AttributeError: # TODO Remove try/except closure after drop Django 2.2 + try: + return side.queryset.query + except AttributeError: + return None + elif h_class in UNCACHABLE_FUNCS: + raise UncachableQuery def _find_rhs_lhs_subquery(side): diff --git a/docs/quickstart.rst b/docs/quickstart.rst index bf4aeb1..948f28e 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -144,6 +144,16 @@ Settings some issues, especially during tests. Run ``./manage.py invalidate_cachalot`` after changing this setting. +``CACHALOT_ADDITIONAL_TABLES`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Default: ``list()`` +:Description: + Sequence of SQL table names that are not included in your Django + apps such as unmanaged models. Cachalot caches models that Django + does not manage, so if you want to ignore/not-cache those models, + then add them here. + ``CACHALOT_QUERY_KEYGEN`` ~~~~~~~~~~~~~~~~~~~~~~~~~