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.
#
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
2006-07-22 04:39:17 +08:00
from django . template 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 ) :
source , origin = self . load_template_source ( template_name , template_dirs )
template = get_template_from_string ( source , name = template_name )
return template , origin
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 ) :
2006-05-02 09:31:56 +08:00
if settings . TEMPLATE_DEBUG :
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 ) :
if hasattr ( loader , ' __iter__ ' ) :
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
2009-12-14 20:08:23 +08:00
def find_template_source ( name , dirs = None ) :
# For backward compatibility
import warnings
warnings . warn (
" `django.template.loaders.find_template_source` is deprecated; use `django.template.loaders.find_template` instead. " ,
PendingDeprecationWarning
)
template , origin = find_template ( name , dirs )
if hasattr ( template , ' render ' ) :
raise Exception ( " Found a compiled template that is incompatible with the deprecated `django.template.loaders.find_template_source` function. " )
return template , origin
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 )
if context_instance :
context_instance . update ( dictionary )
else :
context_instance = Context ( dictionary )
2007-06-22 15:15:04 +08:00
return t . render ( context_instance )
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. "
for template_name in template_name_list :
try :
return get_template ( template_name )
except TemplateDoesNotExist :
continue
# If we get here, none of the templates could be loaded
2010-01-11 02:36:20 +08:00
raise TemplateDoesNotExist ( ' , ' . join ( template_name_list ) )
2005-10-15 04:10:13 +08:00
2006-05-02 09:31:56 +08:00
add_to_builtins ( ' django.template.loader_tags ' )