==========================================How to implement a custom template backend==========================================Custom backends---------------Here's how to implement a custom template backend in order to use anothertemplate 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 afictional ``foobar`` template library::from django.template import TemplateDoesNotExist, TemplateSyntaxErrorfrom django.template.backends.base import BaseEnginefrom django.template.backends.utils import csrf_input_lazy, csrf_token_lazyimport foobarclass 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 = templatedef render(self, context=None, request=None):if context is None:context = {}if request is not None:context['request'] = requestcontext['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 templateerror arises. Custom template engines can use these hooks to enhance thetraceback information that appears to users. The following hooks are available:.. _template-postmortem:Template postmortem~~~~~~~~~~~~~~~~~~~The postmortem appears when :exc:`~django.template.TemplateDoesNotExist` israised. It lists the template engines and loaders that were used when trying tofind a given template. For example, if two Django engines are configured, thepostmortem will appear like:.. image:: _images/postmortem.pngCustom 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 displaythe line the error happened on. For example:.. image:: _images/template-lines.pngCustom engines can populate this information by setting a ``template_debug``attribute on exceptions raised during parsing and rendering. This attribute isa :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 theexception occurred on. This is for context, so it shouldn't contain more than20 lines or so.* ``'line'``: The line number on which the exception occurred.* ``'before'``: The content on the error line before the token that raised theerror.* ``'during'``: The token that raised the error.* ``'after'``: The content on the error line after the token that raised theerror.* ``'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 availablethrough the ``template.origin`` attribute. This enables debug information to bedisplayed in the :ref:`template postmortem <template-postmortem>`, as well asin 3rd-party libraries, like the `Django Debug Toolbar`_.Custom engines can provide their own ``template.origin`` information bycreating 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 thetemplate loading methods.* ``'loader_name'``: An optional string identifying the function or class usedto load the template, e.g. ``django.template.loaders.filesystem.Loader``... _DEP 182: https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst.. _Django Debug Toolbar: https://github.com/jazzband/django-debug-toolbar/