App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / django / template / loader.py
blob418501713db4097e740a877f9873ebf2cccd0ff9
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 # A loader may return an already-compiled template instead of the actual
16 # template source. In that case the path returned should be None, since the
17 # path information is associated with the template during the compilation,
18 # which has already been done.
20 # Each loader should have an "is_usable" attribute set. This is a boolean that
21 # specifies whether the loader can be used in this Python installation. Each
22 # loader is responsible for setting this when it's initialized.
24 # For example, the eggs loader (which is capable of loading templates from
25 # Python eggs) sets is_usable to False if the "pkg_resources" module isn't
26 # installed, because pkg_resources is necessary to read eggs.
28 from django.core.exceptions import ImproperlyConfigured
29 from django.template.base import Origin, Template, Context, TemplateDoesNotExist, add_to_builtins
30 from django.utils.importlib import import_module
31 from django.conf import settings
33 template_source_loaders = None
35 class BaseLoader(object):
36 is_usable = False
38 def __init__(self, *args, **kwargs):
39 pass
41 def __call__(self, template_name, template_dirs=None):
42 return self.load_template(template_name, template_dirs)
44 def load_template(self, template_name, template_dirs=None):
45 source, display_name = self.load_template_source(template_name, template_dirs)
46 origin = make_origin(display_name, self.load_template_source, template_name, template_dirs)
47 try:
48 template = get_template_from_string(source, origin, template_name)
49 return template, None
50 except TemplateDoesNotExist:
51 # If compiling the template we found raises TemplateDoesNotExist, back off to
52 # returning the source and display name for the template we were asked to load.
53 # This allows for correct identification (later) of the actual template that does
54 # not exist.
55 return source, display_name
57 def load_template_source(self, template_name, template_dirs=None):
58 """
59 Returns a tuple containing the source and origin for the given template
60 name.
62 """
63 raise NotImplementedError
65 def reset(self):
66 """
67 Resets any state maintained by the loader instance (e.g., cached
68 templates or cached loader modules).
70 """
71 pass
73 class LoaderOrigin(Origin):
74 def __init__(self, display_name, loader, name, dirs):
75 super(LoaderOrigin, self).__init__(display_name)
76 self.loader, self.loadname, self.dirs = loader, name, dirs
78 def reload(self):
79 return self.loader(self.loadname, self.dirs)[0]
81 def make_origin(display_name, loader, name, dirs):
82 if settings.TEMPLATE_DEBUG and display_name:
83 return LoaderOrigin(display_name, loader, name, dirs)
84 else:
85 return None
87 def find_template_loader(loader):
88 if isinstance(loader, (tuple, list)):
89 loader, args = loader[0], loader[1:]
90 else:
91 args = []
92 if isinstance(loader, basestring):
93 module, attr = loader.rsplit('.', 1)
94 try:
95 mod = import_module(module)
96 except ImportError, e:
97 raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e))
98 try:
99 TemplateLoader = getattr(mod, attr)
100 except AttributeError, e:
101 raise ImproperlyConfigured('Error importing template source loader %s: "%s"' % (loader, e))
103 if hasattr(TemplateLoader, 'load_template_source'):
104 func = TemplateLoader(*args)
105 else:
106 # Try loading module the old way - string is full path to callable
107 if args:
108 raise ImproperlyConfigured("Error importing template source loader %s - can't pass arguments to function-based loader." % loader)
109 func = TemplateLoader
111 if not func.is_usable:
112 import warnings
113 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)
114 return None
115 else:
116 return func
117 else:
118 raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader')
120 def find_template(name, dirs=None):
121 # Calculate template_source_loaders the first time the function is executed
122 # because putting this logic in the module-level namespace may cause
123 # circular import errors. See Django ticket #1292.
124 global template_source_loaders
125 if template_source_loaders is None:
126 loaders = []
127 for loader_name in settings.TEMPLATE_LOADERS:
128 loader = find_template_loader(loader_name)
129 if loader is not None:
130 loaders.append(loader)
131 template_source_loaders = tuple(loaders)
132 for loader in template_source_loaders:
133 try:
134 source, display_name = loader(name, dirs)
135 return (source, make_origin(display_name, loader, name, dirs))
136 except TemplateDoesNotExist:
137 pass
138 raise TemplateDoesNotExist(name)
140 def get_template(template_name):
142 Returns a compiled Template object for the given template name,
143 handling template inheritance recursively.
145 template, origin = find_template(template_name)
146 if not hasattr(template, 'render'):
147 # template needs to be compiled
148 template = get_template_from_string(template, origin, template_name)
149 return template
151 def get_template_from_string(source, origin=None, name=None):
153 Returns a compiled Template object for the given template code,
154 handling template inheritance recursively.
156 return Template(source, origin, name)
158 def render_to_string(template_name, dictionary=None, context_instance=None):
160 Loads the given template_name and renders it with the given dictionary as
161 context. The template_name may be a string to load a single template using
162 get_template, or it may be a tuple to use select_template to find one of
163 the templates in the list. Returns a string.
165 dictionary = dictionary or {}
166 if isinstance(template_name, (list, tuple)):
167 t = select_template(template_name)
168 else:
169 t = get_template(template_name)
170 if not context_instance:
171 return t.render(Context(dictionary))
172 # Add the dictionary to the context stack, ensuring it gets removed again
173 # to keep the context_instance in the same state it started in.
174 context_instance.update(dictionary)
175 try:
176 return t.render(context_instance)
177 finally:
178 context_instance.pop()
180 def select_template(template_name_list):
181 "Given a list of template names, returns the first that can be loaded."
182 if not template_name_list:
183 raise TemplateDoesNotExist("No template names provided")
184 not_found = []
185 for template_name in template_name_list:
186 try:
187 return get_template(template_name)
188 except TemplateDoesNotExist, e:
189 if e.args[0] not in not_found:
190 not_found.append(e.args[0])
191 continue
192 # If we get here, none of the templates could be loaded
193 raise TemplateDoesNotExist(', '.join(not_found))
195 add_to_builtins('django.template.loader_tags')