app/django/template/loader.py
changeset 54 03e267d67478
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 # Wrapper for loading templates from storage of some sort (e.g. filesystem, database).
       
     2 #
       
     3 # This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
       
     4 # Each loader is expected to have this interface:
       
     5 #
       
     6 #    callable(name, dirs=[])
       
     7 #
       
     8 # name is the template name.
       
     9 # dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
       
    10 #
       
    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.
       
    14 #
       
    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.
       
    18 #
       
    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.
       
    22 
       
    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
       
    26 
       
    27 template_source_loaders = None
       
    28 
       
    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
       
    33 
       
    34     def reload(self):
       
    35         return self.loader(self.loadname, self.dirs)[0]
       
    36 
       
    37 def make_origin(display_name, loader, name, dirs):
       
    38     if settings.TEMPLATE_DEBUG:
       
    39         return LoaderOrigin(display_name, loader, name, dirs)
       
    40     else:
       
    41         return None
       
    42 
       
    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         loaders = []
       
    50         for path in settings.TEMPLATE_LOADERS:
       
    51             i = path.rfind('.')
       
    52             module, attr = path[:i], path[i+1:]
       
    53             try:
       
    54                 mod = __import__(module, globals(), locals(), [attr])
       
    55             except ImportError, e:
       
    56                 raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e)
       
    57             try:
       
    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:
       
    62                 import warnings
       
    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)
       
    64             else:
       
    65                 loaders.append(func)
       
    66         template_source_loaders = tuple(loaders)
       
    67     for loader in template_source_loaders:
       
    68         try:
       
    69             source, display_name = loader(name, dirs)
       
    70             return (source, make_origin(display_name, loader, name, dirs))
       
    71         except TemplateDoesNotExist:
       
    72             pass
       
    73     raise TemplateDoesNotExist, name
       
    74 
       
    75 def get_template(template_name):
       
    76     """
       
    77     Returns a compiled Template object for the given template name,
       
    78     handling template inheritance recursively.
       
    79     """
       
    80     source, origin = find_template_source(template_name)
       
    81     template = get_template_from_string(source, origin, template_name)
       
    82     return template
       
    83 
       
    84 def get_template_from_string(source, origin=None, name=None):
       
    85     """
       
    86     Returns a compiled Template object for the given template code,
       
    87     handling template inheritance recursively.
       
    88     """
       
    89     return Template(source, origin, name)
       
    90 
       
    91 def render_to_string(template_name, dictionary=None, context_instance=None):
       
    92     """
       
    93     Loads the given template_name and renders it with the given dictionary as
       
    94     context. The template_name may be a string to load a single template using
       
    95     get_template, or it may be a tuple to use select_template to find one of
       
    96     the templates in the list. Returns a string.
       
    97     """
       
    98     dictionary = dictionary or {}
       
    99     if isinstance(template_name, (list, tuple)):
       
   100         t = select_template(template_name)
       
   101     else:
       
   102         t = get_template(template_name)
       
   103     if context_instance:
       
   104         context_instance.update(dictionary)
       
   105     else:
       
   106         context_instance = Context(dictionary)
       
   107     return t.render(context_instance)
       
   108 
       
   109 def select_template(template_name_list):
       
   110     "Given a list of template names, returns the first that can be loaded."
       
   111     for template_name in template_name_list:
       
   112         try:
       
   113             return get_template(template_name)
       
   114         except TemplateDoesNotExist:
       
   115             continue
       
   116     # If we get here, none of the templates could be loaded
       
   117     raise TemplateDoesNotExist, ', '.join(template_name_list)
       
   118 
       
   119 add_to_builtins('django.template.loader_tags')