diff --git a/LICENSE b/LICENSE index 0d17aff..f06dc6f 100644 --- a/LICENSE +++ b/LICENSE @@ -28,6 +28,35 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Parts are (c) 2011 ANEXIA Internetdienstleistungs GmbH. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the author nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + This software includes CodeMirror released under the following license: diff --git a/dbtemplates/loader.py b/dbtemplates/loader.py index c5cc4a4..767a2e3 100644 --- a/dbtemplates/loader.py +++ b/dbtemplates/loader.py @@ -1,9 +1,13 @@ +# Parts of this file are (c) 2011 ANEXIA Internetdienstleistungs GmbH. +# For further copyrights and licensing information see the LICENSE +# file that was distributed with this file. from django.contrib.sites.models import Site from django.template import TemplateDoesNotExist from dbtemplates.conf import settings from dbtemplates.models import Template from dbtemplates.utils.cache import cache, get_cache_key, set_and_return +from dbtemplates.utils.cache import get_cache_notfound_key from django.template.loader import BaseLoader @@ -19,6 +23,18 @@ class Loader(BaseLoader): is_usable = True def load_template_source(self, template_name, template_dirs=None): + # The logic should work like this: + # * Try to find the template in the cache. If found, return it. + # * Now check the cache if a lookup for the given template + # has failed lately and hand over control to the next template + # loader waiting in line. + # * If this still did not fail we first try to find a site-specific + # template in the database. + # * On a failure from our last attempt we try to load the global + # template from the database. + # * If all of the above steps have failed we generate a new key + # in the cache indicating that queries failed, with the current + # timestamp. site = Site.objects.get_current() display_name = 'dbtemplates:%s:%s:%s' % (settings.DATABASE_ENGINE, template_name, site.domain) @@ -30,15 +46,32 @@ class Loader(BaseLoader): return backend_template, template_name except: pass + + # Not found in cache, move on. + cache_notfound_key = get_cache_notfound_key(template_name) + if cache: + try: + notfound = cache.get(cache_notfound_key) + if notfound: + raise TemplateDoesNotExist(template_name) + except: + raise TemplateDoesNotExist(template_name) + + # Not marked as not-found, move on... + try: - template = Template.objects.get(name__exact=template_name) + template = Template.objects.get(name__exact=template_name, + sites__in=[site.id]) return set_and_return(cache_key, template.content, display_name) - except (Template.MultipleObjectsReturned, Template.DoesNotExist): + except Template.DoesNotExist: try: template = Template.objects.get( - name__exact=template_name, sites__in=[site.id]) + name__exact=template_name) return set_and_return( cache_key, template.content, display_name) except Template.DoesNotExist: pass + + # Mark as not-found in cache. + cache.set(cache_notfound_key, '1') raise TemplateDoesNotExist(template_name) diff --git a/dbtemplates/utils/cache.py b/dbtemplates/utils/cache.py index 65ac768..fa317ef 100644 --- a/dbtemplates/utils/cache.py +++ b/dbtemplates/utils/cache.py @@ -1,3 +1,6 @@ +# Parts of this file are (c) 2011 ANEXIA Internetdienstleistungs GmbH. +# For further copyrights and licensing information see the LICENSE +# file that was distributed with this file. from django.core.cache import get_cache from django.contrib.sites.models import Site @@ -15,6 +18,12 @@ def get_cache_key(name): current_site = Site.objects.get_current() return 'dbtemplates::%s::%s' % (name, current_site.pk) +def get_cache_notfound_key(name): + return get_cache_key(name)+'::notfound' + +def remove_notfound_key(instance): + # Remove notfound key as soon as we save the template. + cache.delete(get_cache_notfound_key(instance.name)) def set_and_return(cache_key, content, display_name): # Save in cache backend explicitly if manually deleted or invalidated @@ -29,6 +38,7 @@ def add_template_to_cache(instance, **kwargs): in the database was added or changed. """ remove_cached_template(instance) + remove_notfound_key(instance) cache.set(get_cache_key(instance.name), instance.content)