1 # Wrapper for loading templates from storage of some sort (e.g. filesystem, database).
3 # This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
4 # Each loader is expected to have this interface:
6 # callable(name, dirs=[])
8 # name is the template name.
9 # dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
11 # The loader should return a tuple of (template_source, path). The path returned
12 # might be shown to the user for debugging purposes, so it should identify where
13 # the template was loaded from.
15 # Each loader should have an "is_usable" attribute set. This is a boolean that
16 # specifies whether the loader can be used in this Python installation. Each
17 # loader is responsible for setting this when it's initialized.
19 # For example, the eggs loader (which is capable of loading templates from
20 # Python eggs) sets is_usable to False if the "pkg_resources" module isn't
21 # installed, because pkg_resources is necessary to read eggs.
23 from django
.core
.exceptions
import ImproperlyConfigured
24 from django
.template
import Origin
, Template
, Context
, TemplateDoesNotExist
, add_to_builtins
25 from django
.conf
import settings
27 template_source_loaders
= None
29 class LoaderOrigin(Origin
):
30 def __init__(self
, display_name
, loader
, name
, dirs
):
31 super(LoaderOrigin
, self
).__init
__(display_name
)
32 self
.loader
, self
.loadname
, self
.dirs
= loader
, name
, dirs
35 return self
.loader(self
.loadname
, self
.dirs
)[0]
37 def make_origin(display_name
, loader
, name
, dirs
):
38 if settings
.TEMPLATE_DEBUG
:
39 return LoaderOrigin(display_name
, loader
, name
, dirs
)
43 def find_template_source(name
, dirs
=None):
44 # Calculate template_source_loaders the first time the function is executed
45 # because putting this logic in the module-level namespace may cause
46 # circular import errors. See Django ticket #1292.
47 global template_source_loaders
48 if template_source_loaders
is None:
49 template_source_loaders
= []
50 for path
in settings
.TEMPLATE_LOADERS
:
52 module
, attr
= path
[:i
], path
[i
+1:]
54 mod
= __import__(module
, globals(), locals(), [attr
])
55 except ImportError, e
:
56 raise ImproperlyConfigured
, 'Error importing template source loader %s: "%s"' % (module
, e
)
58 func
= getattr(mod
, attr
)
59 except AttributeError:
60 raise ImproperlyConfigured
, 'Module "%s" does not define a "%s" callable template source loader' % (module
, attr
)
61 if not func
.is_usable
:
63 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." % path
)
65 template_source_loaders
.append(func
)
66 for loader
in template_source_loaders
:
68 source
, display_name
= loader(name
, dirs
)
69 return (source
, make_origin(display_name
, loader
, name
, dirs
))
70 except TemplateDoesNotExist
:
72 raise TemplateDoesNotExist
, name
74 def get_template(template_name
):
76 Returns a compiled Template object for the given template name,
77 handling template inheritance recursively.
79 source
, origin
= find_template_source(template_name
)
80 template
= get_template_from_string(source
, origin
, template_name
)
83 def get_template_from_string(source
, origin
=None, name
=None):
85 Returns a compiled Template object for the given template code,
86 handling template inheritance recursively.
88 return Template(source
, origin
, name
)
90 def render_to_string(template_name
, dictionary
=None, context_instance
=None):
92 Loads the given template_name and renders it with the given dictionary as
93 context. The template_name may be a string to load a single template using
94 get_template, or it may be a tuple to use select_template to find one of
95 the templates in the list. Returns a string.
97 dictionary
= dictionary
or {}
98 if isinstance(template_name
, (list, tuple)):
99 t
= select_template(template_name
)
101 t
= get_template(template_name
)
103 context_instance
.update(dictionary
)
105 context_instance
= Context(dictionary
)
106 return t
.render(context_instance
)
108 def select_template(template_name_list
):
109 "Given a list of template names, returns the first that can be loaded."
110 for template_name
in template_name_list
:
112 return get_template(template_name
)
113 except TemplateDoesNotExist
:
115 # If we get here, none of the templates could be loaded
116 raise TemplateDoesNotExist
, ', '.join(template_name_list
)
118 add_to_builtins('django.template.loader_tags')