# -*- coding: utf-8 -*- import logging import uuid import django from django.db.models.signals import post_save, post_delete, m2m_changed from django.db.models.fields.related import RelatedField from .model_cache_sharing.types import ModelCacheInfo from .model_cache_sharing import model_cache_backend """ Signal receivers for django model post_save and post_delete. Used to evict a model cache when an update or delete happens on the model. For compatibility with Django 1.5 these receivers live in models.py """ logger = logging.getLogger(__name__) def update_model_cache(table_name): """ Updates model cache by generating a new key for the model """ model_cache_info = ModelCacheInfo(table_name, uuid.uuid4().hex) model_cache_backend.share_model_cache_info(model_cache_info) def invalidate_model_cache(sender, instance, **kwargs): """ Signal receiver for models to invalidate model cache of sender and related models. Model cache is invalidated by generating new key for each model. Parameters ~~~~~~~~~~ sender The model class instance The actual instance being saved. """ logger.debug('Received post_save/post_delete signal from sender {0}'.format(sender)) if django.VERSION >= (1, 8): related_tables = set( [f.related_model._meta.db_table for f in sender._meta.get_fields() if f.related_model is not None and (((f.one_to_many or f.one_to_one) and f.auto_created) or f.many_to_one or (f.many_to_many and not f.auto_created))]) else: related_tables = set([rel.model._meta.db_table for rel in sender._meta.get_all_related_objects()]) # temporary fix for m2m relations with an intermediate model, goes away after better join caching related_tables |= set([field.rel.to._meta.db_table for field in sender._meta.fields if issubclass(type(field), RelatedField)]) logger.debug('Related tables of sender {0} are {1}'.format(sender, related_tables)) update_model_cache(sender._meta.db_table) for related_table in related_tables: update_model_cache(related_table) def invalidate_m2m_cache(sender, instance, model, **kwargs): """ Signal receiver for models to invalidate model cache for many-to-many relationship. Parameters ~~~~~~~~~~ sender The model class instance The instance whose many-to-many relation is updated. model The class of the objects that are added to, removed from or cleared from the relation. """ logger.debug('Received m2m_changed signals from sender {0}'.format(sender)) update_model_cache(instance._meta.db_table) update_model_cache(model._meta.db_table) post_save.connect(invalidate_model_cache) post_delete.connect(invalidate_model_cache) m2m_changed.connect(invalidate_m2m_cache)