mirror of
				https://github.com/django/django.git
				synced 2025-10-29 00:26:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			174 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| =======================
 | |
| Custom template backend
 | |
| =======================
 | |
| 
 | |
| Custom backends
 | |
| ---------------
 | |
| 
 | |
| Here's how to implement a custom template backend in order to use another
 | |
| template system. A template backend is a class that inherits
 | |
| ``django.template.backends.base.BaseEngine``. It must implement
 | |
| ``get_template()`` and optionally ``from_string()``. Here's an example for a
 | |
| fictional ``foobar`` template library::
 | |
| 
 | |
|     from django.template import TemplateDoesNotExist, TemplateSyntaxError
 | |
|     from django.template.backends.base import BaseEngine
 | |
|     from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
 | |
| 
 | |
|     import foobar
 | |
| 
 | |
| 
 | |
|     class FooBar(BaseEngine):
 | |
| 
 | |
|         # Name of the subdirectory containing the templates for this engine
 | |
|         # inside an installed application.
 | |
|         app_dirname = 'foobar'
 | |
| 
 | |
|         def __init__(self, params):
 | |
|             params = params.copy()
 | |
|             options = params.pop('OPTIONS').copy()
 | |
|             super().__init__(params)
 | |
| 
 | |
|             self.engine = foobar.Engine(**options)
 | |
| 
 | |
|         def from_string(self, template_code):
 | |
|             try:
 | |
|                 return Template(self.engine.from_string(template_code))
 | |
|             except foobar.TemplateCompilationFailed as exc:
 | |
|                 raise TemplateSyntaxError(exc.args)
 | |
| 
 | |
|         def get_template(self, template_name):
 | |
|             try:
 | |
|                 return Template(self.engine.get_template(template_name))
 | |
|             except foobar.TemplateNotFound as exc:
 | |
|                 raise TemplateDoesNotExist(exc.args, backend=self)
 | |
|             except foobar.TemplateCompilationFailed as exc:
 | |
|                 raise TemplateSyntaxError(exc.args)
 | |
| 
 | |
| 
 | |
|     class Template:
 | |
| 
 | |
|         def __init__(self, template):
 | |
|             self.template = template
 | |
| 
 | |
|         def render(self, context=None, request=None):
 | |
|             if context is None:
 | |
|                 context = {}
 | |
|             if request is not None:
 | |
|                 context['request'] = request
 | |
|                 context['csrf_input'] = csrf_input_lazy(request)
 | |
|                 context['csrf_token'] = csrf_token_lazy(request)
 | |
|             return self.template.render(context)
 | |
| 
 | |
| See `DEP 182`_ for more information.
 | |
| 
 | |
| .. _template-debug-integration:
 | |
| 
 | |
| Debug integration for custom engines
 | |
| ------------------------------------
 | |
| 
 | |
| The Django debug page has hooks to provide detailed information when a template
 | |
| error arises. Custom template engines can use these hooks to enhance the
 | |
| traceback information that appears to users. The following hooks are available:
 | |
| 
 | |
| .. _template-postmortem:
 | |
| 
 | |
| Template postmortem
 | |
| ~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| The postmortem appears when :exc:`~django.template.TemplateDoesNotExist` is
 | |
| raised. It lists the template engines and loaders that were used when trying to
 | |
| find a given template. For example, if two Django engines are configured, the
 | |
| postmortem will appear like:
 | |
| 
 | |
| .. image:: _images/postmortem.png
 | |
| 
 | |
| Custom engines can populate the postmortem by passing the ``backend`` and
 | |
| ``tried`` arguments when raising :exc:`~django.template.TemplateDoesNotExist`.
 | |
| Backends that use the postmortem :ref:`should specify an origin
 | |
| <template-origin-api>` on the template object.
 | |
| 
 | |
| Contextual line information
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| If an error happens during template parsing or rendering, Django can display
 | |
| the line the error happened on. For example:
 | |
| 
 | |
| .. image:: _images/template-lines.png
 | |
| 
 | |
| Custom engines can populate this information by setting a ``template_debug``
 | |
| attribute on exceptions raised during parsing and rendering. This attribute is
 | |
| a :class:`dict` with the following values:
 | |
| 
 | |
| * ``'name'``: The name of the template in which the exception occurred.
 | |
| 
 | |
| * ``'message'``: The exception message.
 | |
| 
 | |
| * ``'source_lines'``: The lines before, after, and including the line the
 | |
|   exception occurred on. This is for context, so it shouldn't contain more than
 | |
|   20 lines or so.
 | |
| 
 | |
| * ``'line'``: The line number on which the exception occurred.
 | |
| 
 | |
| * ``'before'``: The content on the error line before the token that raised the
 | |
|   error.
 | |
| 
 | |
| * ``'during'``: The token that raised the error.
 | |
| 
 | |
| * ``'after'``: The content on the error line after the token that raised the
 | |
|   error.
 | |
| 
 | |
| * ``'total'``: The number of lines in ``source_lines``.
 | |
| 
 | |
| * ``'top'``: The line number where ``source_lines`` starts.
 | |
| 
 | |
| * ``'bottom'``: The line number where ``source_lines`` ends.
 | |
| 
 | |
| Given the above template error, ``template_debug`` would look like::
 | |
| 
 | |
|     {
 | |
|         'name': '/path/to/template.html',
 | |
|         'message': "Invalid block tag: 'syntax'",
 | |
|         'source_lines': [
 | |
|             (1, 'some\n'),
 | |
|             (2, 'lines\n'),
 | |
|             (3, 'before\n'),
 | |
|             (4, 'Hello {% syntax error %} {{ world }}\n'),
 | |
|             (5, 'some\n'),
 | |
|             (6, 'lines\n'),
 | |
|             (7, 'after\n'),
 | |
|             (8, ''),
 | |
|         ],
 | |
|         'line': 4,
 | |
|         'before': 'Hello ',
 | |
|         'during': '{% syntax error %}',
 | |
|         'after': ' {{ world }}\n',
 | |
|         'total': 9,
 | |
|         'bottom': 9,
 | |
|         'top': 1,
 | |
|     }
 | |
| 
 | |
| .. _template-origin-api:
 | |
| 
 | |
| Origin API and 3rd-party integration
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| Django templates have an :class:`~django.template.base.Origin` object available
 | |
| through the ``template.origin`` attribute. This enables debug information to be
 | |
| displayed in the :ref:`template postmortem <template-postmortem>`, as well as
 | |
| in 3rd-party libraries, like the `Django Debug Toolbar`_.
 | |
| 
 | |
| Custom engines can provide their own ``template.origin`` information by
 | |
| creating an object that specifies the following attributes:
 | |
| 
 | |
| * ``'name'``: The full path to the template.
 | |
| 
 | |
| * ``'template_name'``: The relative path to the template as passed into the
 | |
|   template loading methods.
 | |
| 
 | |
| * ``'loader_name'``: An optional string identifying the function or class used
 | |
|   to load the template, e.g. ``django.template.loaders.filesystem.Loader``.
 | |
| 
 | |
| .. _DEP 182: https://github.com/django/deps/blob/master/final/0182-multiple-template-engines.rst
 | |
| .. _Django Debug Toolbar: https://github.com/jazzband/django-debug-toolbar
 |