django-cachalot/cachalot/api.py
Andrew-Chen-Wang 602cdcee1d
Version 2.2.0 (#146)
This PR upgrades cachalot to version 2.2.0 allowing for anyone to install cachalot at any Django package above 1.11. All tests currently function now.

* Added mysql as a service to fix Travis CI

* Removed tox dependency

* Removed upper limit on Django and support 2.2-3.0 CI Test
* Cachalot will only say "officially supports" while removing upper limit to not hinder anyone's progress.
* Added Python 3.8 and Django 2.2 and 3.0 to CI tests

- Max is 200 and we'll get there quickly if we add another Python version. Utilizes #127
- Keep dependencies for six and django.utils.six

* Correctly run Travis test by updating tox.ini
* Originally using tox syntax but changed testenv to travis so that travis env and travis dependencies and stuff are used

* Tox tests should start running command

* testenv without dependencies broke travis. New spot in Tox
* testenv without dependencies broke travis
* I can't figure out where testenv is supposed to be
* Good thing there's squash

* Added missing six in test
* Also added six package to Tox for Django 3.0 coverage.
* The missing six package caused several problems in several tests due to using an incorrect DB

* Resolves #138
* Need to add the panels here in order to satisfy tests

* Adds CachalotPanel to Python 2 backwards compatibility
* Forgot super class took those like save()

* Added databases to certain test cases
* APITestCase, DebugToolbarTestCase, SignalsTestCase required a database set
* Fixes errors like these: https://travis-ci.org/noripyt/django-cachalot/jobs/648691385#L4892

* Dropped OFFICIAL support for Python 3.4 + MySQL
* MySQL and its client on 3.4 is f--king up a lot of the testing and I can't bear with it. We can revisit it later, but, honestly, who uses Python 3.4... and if an organization is, then they will either have no problem with Postgres and SQLite or know that MySQL doesn't work.

* Drop Py3.4 from running. Fixed databases
* Now goes with setting's databases rather than hardcoded since some tests don't have other databases.

* Fix ReadTestCase

Django 2.2+ changed self.queryset at line 1000 with self.query=queryset.query

* Django Dependency Removed from utils.py

* Last commit used Django version. This one used try except

* Fixed assertNumQuery; added allow_failures for 3.4
* Primary: More information in test_utils.py with method is_django_21_below_and_is_sqlite
* The problem with the entire build lie in the self.is_sqlite for the tests. SQLite will make 2 queries when creating or destroying or updating instead of 1.
* In summary, if SQLite is the DB and Django

* Changed build matrix to allow failures for 3.4 instead of taking it out completely so that we can get it to work soon.

* Remove -> From function return
* I love backwards compatibility

* SQLite2 in multi_db.py returned incorrect bool

* Django 2.1 and SQLite checker doesn't work for some tests
* Some tests DO HAVE the BEGIN query that is returned... Not sure why. If the next test show completely different WriteTestCase problems, then we need to find alternative.
* Removed check from atomic

* Adjust Django and is_sqlite errors
* CI testing the Tox errors: https://travis-ci.org/noripyt/django-cachalot?utm_medium=notification&utm_source=github_status

* Adjust Django and is_sqlite errors (590 CI)
* CI testing the Tox errors: https://travis-ci.org/noripyt/django-cachalot?utm_medium=notification&utm_source=github_status
* Adjustment 2

* Make include matrix and Adjust Django and is_sqlite errors (594 CI)
* CI testing the Tox errors: https://travis-ci.org/noripyt/django-cachalot?utm_medium=notification&utm_source=github_status
* Adjustment 3

* Adjust Django and is_sqlite errors (596 CI)
* CI testing the Tox errors: https://travis-ci.org/noripyt/django-cachalot?utm_medium=notification&utm_source=github_status
* Adjustment 4
* Added my intro to ReadTheDocs

* Adjust Django and is_sqlite errors (598 CI)
* CI testing the Tox errors: https://travis-ci.org/noripyt/django-cachalot?utm_medium=notification&utm_source=github_status
* Adjustment 5

* Drop Python 3.4 from tests since PyLibMC not cooperating at that level.

* Bump package version up 1 minor for Django 2.2 and 3.0
2020-02-12 00:52:12 -05:00

131 lines
5.2 KiB
Python

# coding: utf-8
from __future__ import unicode_literals
from django.apps import apps
from django.conf import settings
from django.db import connections
try:
from django.utils.six import string_types
except ImportError:
from six import string_types
from .cache import cachalot_caches
from .settings import cachalot_settings
from .signals import post_invalidation
from .transaction import AtomicCache
from .utils import _invalidate_tables
__all__ = ('invalidate', 'get_last_invalidation')
def _cache_db_tables_iterator(tables, cache_alias, db_alias):
no_tables = not tables
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 db_alias in db_aliases:
if no_tables:
tables = connections[db_alias].introspection.table_names()
if tables:
for cache_alias in cache_aliases:
yield cache_alias, db_alias, tables
def _get_tables(tables_or_models):
for table_or_model in tables_or_models:
if isinstance(table_or_model, string_types) and '.' in table_or_model:
try:
table_or_model = apps.get_model(table_or_model)
except LookupError:
pass
yield (table_or_model if isinstance(table_or_model, string_types)
else table_or_model._meta.db_table)
def invalidate(*tables_or_models, **kwargs):
"""
Clears what was cached by django-cachalot implying one or more SQL tables
or models from ``tables_or_models``.
If ``tables_or_models`` is not specified, all tables found in the database
(including those outside Django) are invalidated.
If ``cache_alias`` is specified, it only clears the SQL queries stored
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.
:arg tables_or_models: SQL tables names, models or models lookups
(or a combination)
:type tables_or_models: tuple of strings or models
:arg cache_alias: Alias from the Django ``CACHES`` setting
:type cache_alias: string or NoneType
:arg db_alias: Alias from the Django ``DATABASES`` setting
:type db_alias: string or NoneType
:returns: Nothing
:rtype: NoneType
"""
# TODO: Replace with positional arguments when we drop Python 2 support.
cache_alias = kwargs.pop('cache_alias', None)
db_alias = kwargs.pop('db_alias', None)
for k in kwargs:
raise TypeError(
"invalidate() got an unexpected keyword argument '%s'" % k)
send_signal = False
invalidated = set()
for cache_alias, db_alias, tables in _cache_db_tables_iterator(
list(_get_tables(tables_or_models)), cache_alias, db_alias):
cache = cachalot_caches.get_cache(cache_alias, db_alias)
if not isinstance(cache, AtomicCache):
send_signal = True
_invalidate_tables(cache, db_alias, tables)
invalidated.update(tables)
if send_signal:
for table in invalidated:
post_invalidation.send(table, db_alias=db_alias)
def get_last_invalidation(*tables_or_models, **kwargs):
"""
Returns the timestamp of the most recent invalidation of the given
``tables_or_models``. If ``tables_or_models`` is not specified,
all tables found in the database (including those outside Django) are used.
If ``cache_alias`` is specified, it only fetches invalidations
in this cache, otherwise invalidations in all caches are fetched.
If ``db_alias`` is specified, it only fetches invalidations
for this database, otherwise invalidations for all databases are fetched.
:arg tables_or_models: SQL tables names, models or models lookups
(or a combination)
:type tables_or_models: tuple of strings or models
:arg cache_alias: Alias from the Django ``CACHES`` setting
:type cache_alias: string or NoneType
:arg db_alias: Alias from the Django ``DATABASES`` setting
:type db_alias: string or NoneType
:returns: The timestamp of the most recent invalidation
:rtype: float
"""
# TODO: Replace with positional arguments when we drop Python 2 support.
cache_alias = kwargs.pop('cache_alias', None)
db_alias = kwargs.pop('db_alias', None)
for k in kwargs:
raise TypeError("get_last_invalidation() got an unexpected "
"keyword argument '%s'" % k)
last_invalidation = 0.0
for cache_alias, db_alias, tables in _cache_db_tables_iterator(
list(_get_tables(tables_or_models)), cache_alias, db_alias):
get_table_cache_key = cachalot_settings.CACHALOT_TABLE_KEYGEN
table_cache_keys = [get_table_cache_key(db_alias, t) for t in tables]
invalidations = cachalot_caches.get_cache(
cache_alias, db_alias).get_many(table_cache_keys).values()
if invalidations:
current_last_invalidation = max(invalidations)
if current_last_invalidation > last_invalidation:
last_invalidation = current_last_invalidation
return last_invalidation