Use the cache to remember which templates were not found in the database.

Also reverse the logic of the database lookup. First check if there is
site-specific template in the database and only if that fails
try to load the global template.
This should cut down the number of database queries that need to be executed,
especially in a loop that includes a given template that does not exist
in the database.

Signed-off-by: Stephan Peijnik <spe@anexia.at>
This commit is contained in:
Stephan Peijnik 2011-07-21 15:19:20 +02:00
parent 29cedc5271
commit 4a0ebb640e
3 changed files with 75 additions and 3 deletions

29
LICENSE
View file

@ -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:

View file

@ -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)

View file

@ -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)