Adds the invalidate_cachalot Django command.

This commit is contained in:
Bertrand Bordage 2015-02-18 03:03:32 +01:00
parent beacea0a8b
commit 0c8180a6e7
7 changed files with 74 additions and 18 deletions

View file

@ -3,7 +3,6 @@
from __future__ import unicode_literals
from django.conf import settings
from django.db import connection
from .cache import cachalot_caches
from .utils import _get_table_cache_key, _invalidate_table_cache_keys
@ -12,16 +11,24 @@ from .utils import _get_table_cache_key, _invalidate_table_cache_keys
__all__ = ('invalidate_tables', 'invalidate_models', 'invalidate_all')
def _aliases_iterator(cache_alias, db_alias):
cache_aliases = settings.CACHES if cache_alias is None else (cache_alias,)
db_aliases = settings.DATABASES if db_alias is None else (db_alias,)
for cache_alias in cache_aliases:
for db_alias in db_aliases:
yield cache_alias, db_alias
def invalidate_tables(tables, cache_alias=None, db_alias=None):
"""
Clears what was cached by django-cachalot implying one or more SQL tables
from ``tables``.
If ``cache_alias`` is specified, it only clears the SQL queries stored
on this cache, otherwise the current cache is cleared.
on this cache, otherwise queries from all caches are cleared.
If ``db_alias`` is specified, it only clears the SQL queries executed
on this database, otherwise queries from the current database are cleared.
on this database, otherwise queries from all databases are cleared.
:arg tables: SQL tables names
:type tables: iterable of strings
@ -33,12 +40,10 @@ def invalidate_tables(tables, cache_alias=None, db_alias=None):
:rtype: NoneType
"""
if db_alias is None:
db_alias = connection.alias
table_cache_keys = [_get_table_cache_key(db_alias, t) for t in tables]
cache = cachalot_caches.get_cache(cache_alias)
_invalidate_table_cache_keys(cache, table_cache_keys)
for cache_alias, db_alias in _aliases_iterator(cache_alias, db_alias):
table_cache_keys = [_get_table_cache_key(db_alias, t) for t in tables]
cache = cachalot_caches.get_cache(cache_alias)
_invalidate_table_cache_keys(cache, table_cache_keys)
def invalidate_models(models, cache_alias=None, db_alias=None):
@ -65,7 +70,7 @@ def invalidate_all(cache_alias=None, db_alias=None):
Clears everything that was cached by django-cachalot.
If ``cache_alias`` is specified, it only clears the SQL queries stored
on this cache, otherwise all caches are cleared.
on this cache, otherwise queries from all caches are cleared.
If ``db_alias`` is specified, it only clears the SQL queries executed
on this database, otherwise queries from all databases are cleared.
@ -78,8 +83,5 @@ def invalidate_all(cache_alias=None, db_alias=None):
:rtype: NoneType
"""
cache_aliases = settings.CACHES if cache_alias is None else (cache_alias,)
db_aliases = settings.DATABASES if db_alias is None else (db_alias,)
for cache_alias in cache_aliases:
for db_alias in db_aliases:
cachalot_caches.invalidate_all(cache_alias, db_alias)
for cache_alias, db_alias in _aliases_iterator(cache_alias, db_alias):
cachalot_caches.invalidate_all(cache_alias, db_alias)

View file

View file

View file

@ -0,0 +1,52 @@
from optparse import make_option
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand
from django.db.models import get_app, get_model, get_models
from ...api import invalidate_all, invalidate_models
class Command(BaseCommand):
help = 'Invalidates the cache keys set by django-cachalot.'
args = '[app_label[.modelname] [...]]'
option_list = BaseCommand.option_list + (
make_option('-c', '--cache', action='store', dest='cache_alias',
type='choice', choices=settings.CACHES.keys(),
help='Cache alias from the CACHES setting.'),
make_option('-d', '--db', action='store', dest='db_alias',
type='choice', choices=settings.DATABASES.keys(),
help='Database alias from the DATABASES setting.'),
)
def handle(self, *args, **options):
cache_alias = options['cache_alias']
db_alias = options['db_alias']
verbosity = options['verbosity']
models = []
for arg in args:
try:
app = get_app(arg)
except ImproperlyConfigured:
app_label = '.'.join(arg.split('.')[:-1])
model_name = arg.split('.')[-1]
models.append(get_model(app_label, model_name))
else:
models.extend(get_models(app))
cache_str = '' if cache_alias is None else "on cache '%s'" % cache_alias
db_str = '' if db_alias is None else "for database '%s'" % db_alias
keys_str = 'keys for %s models' % len(models) if args else 'all keys'
if verbosity != '0':
self.stdout.write(' '.join(filter(bool, ['Invalidating', keys_str,
cache_str, db_str]))
+ '...')
if args:
invalidate_models(models,
cache_alias=cache_alias, db_alias=db_alias)
else:
invalidate_all(cache_alias=cache_alias, db_alias=db_alias)
if verbosity != '0':
self.stdout.write('Cache keys successfully invalidated.')

View file

@ -6,14 +6,14 @@ Limits
Locmem
......
Locmem is a just a dict stored in a single Python process.
Locmem is a just a ``dict`` stored in a single Python process.
Its not shared between processes, so dont use locmem with django-cachalot
in a multi-processes project, if you use RQ or Celery for instance.
Redis
.....
By default, Redis will not evict persistent cache keys (those a ``None``
By default, Redis will not evict persistent cache keys (those with a ``None``
timeout) when the maximum memory has been reached. The cache keys created
by django-cachalot are persistent, so if Redis runs out of memory,
django-cachalot and all other ``cache.set`` will raise

View file

@ -34,6 +34,9 @@ Usage
`django-debug-toolbar <https://github.com/django-debug-toolbar/django-debug-toolbar>`_,
you can add ``'cachalot.panels.CachalotPanel',``
to your ``DEBUG_TOOLBAR_PANELS``
#. If you need to invalidate all django-cachalot cache keys from an external script
 typically after restoring a SQL database , simply run
``./manage.py invalidate_cachalot``
#. Enjoy!

View file

@ -6,4 +6,3 @@ For version 1.0
- Cache raw queries
- Test multi-location caches
- Add a management command to invalidate everything