Repository: django-extensions/django-extensions

Issue:
clear_cache should have an --all option
Hi,

It would make life a bit easier if the `clear_cache` command had an `--all` option, to clear all caches instead of having to name them individually.

Cheers


Discussion:
FYI: `django.core.cache.caches.all()` only returns those caches that have been touched at least once (tested on 1.11 and 2.0). So if we want to implement a "clear all caches", we probably (AFAIU) need to loop over `settings.CACHES` instead of relying on `django.core.cache.caches.all()`.
Yeah sounds really useful.

More then happy to accept a PR for this !

Resolving patch:
diff --git a/django_extensions/management/commands/clear_cache.py b/django_extensions/management/commands/clear_cache.py
--- a/django_extensions/management/commands/clear_cache.py
+++ b/django_extensions/management/commands/clear_cache.py
@@ -1,8 +1,9 @@
 # -*- coding: utf-8 -*-
 # Author: AxiaCore S.A.S. http://axiacore.com
+from django.conf import settings
 from django.core.cache import DEFAULT_CACHE_ALIAS, caches
 from django.core.cache.backends.base import InvalidCacheBackendError
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
 
 from django_extensions.management.utils import signalcommand
 
@@ -14,11 +15,18 @@ class Command(BaseCommand):
     def add_arguments(self, parser):
         parser.add_argument('--cache', action='append',
                             help='Name of cache to clear')
+        parser.add_argument('--all', '-a', action='store_true', default=False,
+                            dest='all_caches', help='Clear all configured caches')
 
     @signalcommand
-    def handle(self, cache, *args, **kwargs):
-        if not cache:
+    def handle(self, cache, all_caches, *args, **kwargs):
+        if not cache and not all_caches:
             cache = [DEFAULT_CACHE_ALIAS]
+        elif cache and all_caches:
+            raise CommandError('Using both --all and --cache is not supported')
+        elif all_caches:
+            cache = getattr(settings, 'CACHES', {DEFAULT_CACHE_ALIAS: {}}).keys()
+
         for key in cache:
             try:
                 caches[key].clear()


Test patch:
diff --git a/tests/test_clear_caches.py b/tests/test_clear_caches.py
new file mode 100644
--- /dev/null
+++ b/tests/test_clear_caches.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+import os
+import mock
+
+from django.core.management import call_command
+from django.core.management.base import CommandError
+from django.test import TestCase
+
+
+DefaultCacheMock = mock.Mock()
+OtherCacheMock = mock.Mock()
+
+
+class ClearCacheTests(TestCase):
+    def setUp(self):
+        self.project_root = os.path.join('tests', 'testapp')
+        self._settings = os.environ.get('DJANGO_SETTINGS_MODULE')
+        os.environ['DJANGO_SETTINGS_MODULE'] = 'django_extensions.settings'
+        DefaultCacheMock.reset_mock()
+        OtherCacheMock.reset_mock()
+
+    def tearDown(self):
+        if self._settings:
+            os.environ['DJANGO_SETTINGS_MODULE'] = self._settings
+
+    def test_called_with_no_arguments(self):
+        with self.settings(BASE_DIR=self.project_root):
+            call_command('clear_cache')
+        DefaultCacheMock.return_value.clear.assert_called()
+        OtherCacheMock.return_value.clear.assert_not_called()
+
+    def test_called_with_explicit_other(self):
+        with self.settings(BASE_DIR=self.project_root):
+            call_command('clear_cache', '--cache', 'other')
+        DefaultCacheMock.return_value.clear.assert_not_called()
+        OtherCacheMock.return_value.clear.assert_called()
+
+    def test_called_with_all_argument(self):
+        with self.settings(BASE_DIR=self.project_root):
+            call_command('clear_cache', '--all')
+        DefaultCacheMock.return_value.clear.assert_called()
+        OtherCacheMock.return_value.clear.assert_called()
+
+    def test_called_with_explicit_all(self):
+        with self.settings(BASE_DIR=self.project_root):
+            call_command('clear_cache', '--cache', 'default', '--cache', 'other')
+        DefaultCacheMock.return_value.clear.assert_called()
+        OtherCacheMock.return_value.clear.assert_called()
+
+    def test_called_with_invalid_arguments(self):
+        with self.settings(BASE_DIR=self.project_root):
+            self.assertRaises(CommandError, call_command, 'clear_cache', '--all', '--cache', 'foo')
diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py
--- a/tests/testapp/settings.py
+++ b/tests/testapp/settings.py
@@ -66,3 +66,12 @@
     'tests.testapp.scripts.invalid_import_script',
     'setup',
 ]
+
+CACHES = {
+    'default': {
+        'BACKEND': 'tests.test_clear_caches.DefaultCacheMock',
+    },
+    'other': {
+        'BACKEND': 'tests.test_clear_caches.OtherCacheMock',
+    },
+}