diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab76bac --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +django_varnish.egg-info/* +*.pyc \ No newline at end of file diff --git a/setup.py b/setup.py index 99bf1a4..695dda0 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name = "django-varnish", - version = '0.1', + version = '0.1.2', url = 'http://opensource.washingtontimes.com/projects/django-varnish/', author = 'Justin Quick', author_email= 'justquick@gmail.com', diff --git a/varnishapp/manager.py b/varnishapp/manager.py index ee9a0c0..f0838fd 100644 --- a/varnishapp/manager.py +++ b/varnishapp/manager.py @@ -3,4 +3,6 @@ from atexit import register manager = VarnishManager(getattr(settings, 'VARNISH_MANAGEMENT_ADDRS', ())) -register(manager.close) \ No newline at end of file +register(manager.close) + +from signals import * \ No newline at end of file diff --git a/varnishapp/signals.py b/varnishapp/signals.py index 8a1454e..1fa2c28 100644 --- a/varnishapp/signals.py +++ b/varnishapp/signals.py @@ -3,9 +3,87 @@ from django.conf import settings from manager import manager +import logging + +logger = logging.getLogger("varnish.invalidation") + + +def purge_old_paths(abs_url): + + """ + If Django redirects app is installed, search for new paths based on given absolute url + and purge all the corresponding old paths to ensure the user gets a redirect to the + new path and not an old cached version of the page if i.e. the slug has changed. + """ + + if "django.contrib.redirects" in settings.INSTALLED_APPS: + from django.contrib.redirects.models import Redirect + + oldpaths = Redirect.objects.filter(new_path=abs_url) + + for p in oldpaths: + + try: + resp = manager.run('ban.url', r'^%s$' % str(p.old_path)) + except: + logger.warn('No varnish instance running. Could not purge %s' % str(p.old_path)) def absolute_url_purge_handler(sender, **kwargs): - manager.run('purge.url', r'^%s$' % kwargs['instance'].get_absolute_url()) + """ + Purges the absolute url of the model instance + NB: It adds $ to the end of the purge, so no urls with parameters etc are purged, + only the url given by get_absolute_url itself + """ + instance = kwargs['instance'] + + if hasattr(instance, 'get_absolute_url'): + abs_url = instance.get_absolute_url() + + try: + banurl = r'^%s$' % abs_url + logger.info("Banning %s" % banurl) + resp = manager.run('ban.url', banurl) + logger.info(resp) + except: + logger.warn('No varnish instance running. Could not purge %s ' % abs_url) + + purge_old_paths(abs_url) + +for model in getattr(settings, 'VARNISH_WATCHED_MODELS', ()): + post_save.connect(absolute_url_purge_handler, sender=get_model(*model.split('.'))) + + + +def api_resource_purge_handler (sender, **kwargs): + + """ + Purges object urls in the API. Requires a get_resource_url on the model that + returns the url of the api resource object base url. If using tastypie that would + look like something like this on a resource named person: + + @models.permalink + def get_resource_url(self): + return ('api_dispatch_detail', (), { + 'resource_name': 'person', + 'api_name': 'v1', + 'pk': self.id}) + + The method will purge all urls *starting* with the url + + """ + instance = kwargs['instance'] + + if hasattr(instance, 'get_resource_url'): + resource_url = instance.get_resource_url() + + try: + manager.run('ban.url', r'^%s' % resource_url) + except: + logger.warn('No varnish instance running. Could not purge %s ' % resource_url) + + purge_old_paths(resource_url) + + for model in getattr(settings, 'VARNISH_WATCHED_MODELS', ()): - post_save.connect(absolute_url_purge_handler, sender=get_model(*model.split('.'))) \ No newline at end of file + post_save.connect(api_resource_purge_handler, sender=get_model(*model.split('.')))