2005-10-15 06:22:12 +08:00
# Wrapper for loading templates from storage of some sort (e.g. filesystem, database).
#
# This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
# Each loader is expected to have this interface:
#
# callable(name, dirs=[])
#
# name is the template name.
# dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
#
2005-11-24 07:10:17 +08:00
# The loader should return a tuple of (template_source, path). The path returned
# might be shown to the user for debugging purposes, so it should identify where
# the template was loaded from.
#
2010-03-02 07:05:35 +08:00
# A loader may return an already-compiled template instead of the actual
# template source. In that case the path returned should be None, since the
# path information is associated with the template during the compilation,
# which has already been done.
#
2005-10-15 06:22:12 +08:00
# Each loader should have an "is_usable" attribute set. This is a boolean that
# specifies whether the loader can be used in this Python installation. Each
# loader is responsible for setting this when it's initialized.
#
# For example, the eggs loader (which is capable of loading templates from
# Python eggs) sets is_usable to False if the "pkg_resources" module isn't
# installed, because pkg_resources is necessary to read eggs.
2005-10-15 04:10:13 +08:00
2005-10-15 06:22:12 +08:00
from django . core . exceptions import ImproperlyConfigured
2010-11-27 13:47:30 +08:00
from django . template . base import Origin , Template , Context , TemplateDoesNotExist , add_to_builtins
2009-03-19 00:55:59 +08:00
from django . utils . importlib import import_module
2006-05-02 09:31:56 +08:00
from django . conf import settings
2005-10-15 06:22:12 +08:00
2006-02-02 13:07:12 +08:00
template_source_loaders = None
2005-10-15 06:22:12 +08:00
2009-12-14 20:08:23 +08:00
class BaseLoader ( object ) :
is_usable = False
def __init__ ( self , * args , * * kwargs ) :
pass
def __call__ ( self , template_name , template_dirs = None ) :
return self . load_template ( template_name , template_dirs )
def load_template ( self , template_name , template_dirs = None ) :
2010-03-02 07:05:35 +08:00
source , display_name = self . load_template_source ( template_name , template_dirs )
origin = make_origin ( display_name , self . load_template_source , template_name , template_dirs )
2010-03-16 22:34:57 +08:00
try :
template = get_template_from_string ( source , origin , template_name )
return template , None
except TemplateDoesNotExist :
2010-03-18 23:35:15 +08:00
# If compiling the template we found raises TemplateDoesNotExist, back off to
2010-03-16 22:34:57 +08:00
# returning the source and display name for the template we were asked to load.
2010-03-18 23:35:15 +08:00
# This allows for correct identification (later) of the actual template that does
2010-03-16 22:34:57 +08:00
# not exist.
return source , display_name
2009-12-14 20:08:23 +08:00
def load_template_source ( self , template_name , template_dirs = None ) :
"""
Returns a tuple containing the source and origin for the given template
name .
"""
raise NotImplementedError
def reset ( self ) :
"""
Resets any state maintained by the loader instance ( e . g . , cached
templates or cached loader modules ) .
"""
pass
2005-11-24 07:10:17 +08:00
class LoaderOrigin ( Origin ) :
def __init__ ( self , display_name , loader , name , dirs ) :
super ( LoaderOrigin , self ) . __init__ ( display_name )
self . loader , self . loadname , self . dirs = loader , name , dirs
def reload ( self ) :
return self . loader ( self . loadname , self . dirs ) [ 0 ]
def make_origin ( display_name , loader , name , dirs ) :
2010-03-02 07:05:35 +08:00
if settings . TEMPLATE_DEBUG and display_name :
2005-11-24 07:10:17 +08:00
return LoaderOrigin ( display_name , loader , name , dirs )
else :
return None
2009-12-14 20:08:23 +08:00
def find_template_loader ( loader ) :
2010-03-18 23:35:15 +08:00
if isinstance ( loader , ( tuple , list ) ) :
2009-12-14 20:08:23 +08:00
loader , args = loader [ 0 ] , loader [ 1 : ]
else :
args = [ ]
if isinstance ( loader , basestring ) :
module , attr = loader . rsplit ( ' . ' , 1 )
try :
mod = import_module ( module )
2009-12-21 06:46:35 +08:00
except ImportError , e :
2009-12-14 20:08:23 +08:00
raise ImproperlyConfigured ( ' Error importing template source loader %s : " %s " ' % ( loader , e ) )
try :
TemplateLoader = getattr ( mod , attr )
except AttributeError , e :
raise ImproperlyConfigured ( ' Error importing template source loader %s : " %s " ' % ( loader , e ) )
if hasattr ( TemplateLoader , ' load_template_source ' ) :
func = TemplateLoader ( * args )
else :
# Try loading module the old way - string is full path to callable
if args :
raise ImproperlyConfigured ( " Error importing template source loader %s - can ' t pass arguments to function-based loader. " % loader )
func = TemplateLoader
if not func . is_usable :
import warnings
warnings . warn ( " Your TEMPLATE_LOADERS setting includes %r , but your Python installation doesn ' t support that type of template loading. Consider removing that line from TEMPLATE_LOADERS. " % loader )
return None
else :
return func
else :
raise ImproperlyConfigured ( ' Loader does not define a " load_template " callable template source loader ' )
def find_template ( name , dirs = None ) :
2006-02-02 13:07:12 +08:00
# Calculate template_source_loaders the first time the function is executed
# because putting this logic in the module-level namespace may cause
# circular import errors. See Django ticket #1292.
global template_source_loaders
if template_source_loaders is None :
2008-05-29 20:40:25 +08:00
loaders = [ ]
2009-12-14 20:08:23 +08:00
for loader_name in settings . TEMPLATE_LOADERS :
loader = find_template_loader ( loader_name )
if loader is not None :
loaders . append ( loader )
2008-05-29 20:40:25 +08:00
template_source_loaders = tuple ( loaders )
2005-10-15 06:22:12 +08:00
for loader in template_source_loaders :
try :
2005-11-25 05:14:42 +08:00
source , display_name = loader ( name , dirs )
2005-11-24 07:10:17 +08:00
return ( source , make_origin ( display_name , loader , name , dirs ) )
2005-10-15 06:29:13 +08:00
except TemplateDoesNotExist :
2005-10-15 06:22:12 +08:00
pass
2010-01-11 02:36:20 +08:00
raise TemplateDoesNotExist ( name )
2005-10-15 04:10:13 +08:00
def get_template ( template_name ) :
"""
Returns a compiled Template object for the given template name ,
handling template inheritance recursively .
"""
2009-12-14 20:08:23 +08:00
template , origin = find_template ( template_name )
if not hasattr ( template , ' render ' ) :
# template needs to be compiled
template = get_template_from_string ( template , origin , template_name )
2006-09-02 17:26:24 +08:00
return template
2005-10-15 04:10:13 +08:00
2006-09-02 17:26:24 +08:00
def get_template_from_string ( source , origin = None , name = None ) :
2005-10-15 04:10:13 +08:00
"""
Returns a compiled Template object for the given template code ,
handling template inheritance recursively .
"""
2006-09-02 17:26:24 +08:00
return Template ( source , origin , name )
2005-10-15 04:10:13 +08:00
2007-06-22 15:15:04 +08:00
def render_to_string ( template_name , dictionary = None , context_instance = None ) :
2005-10-15 04:10:13 +08:00
"""
2007-06-22 15:15:04 +08:00
Loads the given template_name and renders it with the given dictionary as
context . The template_name may be a string to load a single template using
get_template , or it may be a tuple to use select_template to find one of
the templates in the list . Returns a string .
2005-10-15 04:10:13 +08:00
"""
2007-06-22 15:15:04 +08:00
dictionary = dictionary or { }
2005-10-15 04:10:13 +08:00
if isinstance ( template_name , ( list , tuple ) ) :
t = select_template ( template_name )
else :
t = get_template ( template_name )
2011-02-20 12:55:11 +08:00
if not context_instance :
return t . render ( Context ( dictionary ) )
# Add the dictionary to the context stack, ensuring it gets removed again
# to keep the context_instance in the same state it started in.
context_instance . update ( dictionary )
try :
return t . render ( context_instance )
finally :
context_instance . pop ( )
2005-10-15 04:10:13 +08:00
def select_template ( template_name_list ) :
" Given a list of template names, returns the first that can be loaded. "
2011-03-03 08:41:40 +08:00
not_found = [ ]
2005-10-15 04:10:13 +08:00
for template_name in template_name_list :
try :
return get_template ( template_name )
2011-03-03 08:41:40 +08:00
except TemplateDoesNotExist , e :
if e . args [ 0 ] not in not_found :
not_found . append ( e . args [ 0 ] )
2005-10-15 04:10:13 +08:00
continue
# If we get here, none of the templates could be loaded
2011-03-03 08:41:40 +08:00
raise TemplateDoesNotExist ( ' , ' . join ( not_found ) )
2005-10-15 04:10:13 +08:00
2006-05-02 09:31:56 +08:00
add_to_builtins ( ' django.template.loader_tags ' )