Come implementare un backend per template personalizzato

Backend personalizzati

Ecco come implementare un backend di template custom per utilizzare un altro sistema di template. Un backend di template è una classe che eredita da django.template.backends.base.BaseEngine. Deve implementare get_template() ed opzionalmente from_string(). Ecco un esempio di template library fittizia foobar:

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)

Vedi DEP 182 per maggiori informazioni.

Integrazione per il debug di engine custom

La pagina di debug di Django ha hook che forniscono informazioni dettagliate quando si verifica un template error. I motori di template personalizzati possono utilizzare questi hook per aumentare le informazioni di traceback visualizzate dagli utenti. Sono disponibili i seguenti hook:

Postmortem sul template

il postmortem appare quando viene sollevato TemplateDoesNotExist. Fa una lista dei motori di template e dei loader che sono stati usati quando si cercava un determinato template. Per esempio, se sono configurati due motori Django, il postmortem apparrà così:

../../_images/postmortem.png

I motori personalizzati possono popolare il postmortem passando gli argomenti backend e tried quando sollevano TemplateDoesNotExist.I backend che usano il postmortem dovrebbero specificare una origine sull’oggetto di template.

Informazione su linea contestuale

Se viene generato un errore durante il parsing o il rendering del template, Django è in grado di mostrare la riga in cui è presente l’errore. Ad esempio:

../../_images/template-lines.png

I motori personalizzati possono popolare questa informazione impostando un attributo template_debug sulle eccezioni sollevate durante il parsing ed il rendering. Questo attributo è un dict con i seguenti valori:

  • 'name': Il nome del template in cui è avvenuta l’eccezione.
  • 'message': Il messaggio dell’eccezione
  • 'source_lines': Le righe prima, dopo e che includono la riga dove è avvenuta l’eccezione. Questo è per il contesto, quindi non dovrebbe contenere più di 20 righe o giù di lì.
  • 'line': Il numero di riga in cui è avvenuta l’eccezione.
  • 'before': Il contenuto della riga dell’errore prima del token che ha generato l’errore.
  • 'during': Il token che ha generato l’errore.
  • 'after': Il contenuto della riga dell’errore dopo il token che ha generato l’errore.
  • 'total': Il numero di righe in source_lines.
  • 'top': Il numero di riga dove inizia source_lines.
  • 'bottom': Il numero di riga dove termina source_lines.

Dato il template di errore qui sopra, template_debug sarà simile a:

{
    "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,
}

Origin API ed integrazione di terze parti

I template Django hanno un oggetto Origin disponibile attraverso l’attributo template.origin. Questo abilita informazioni di debug da mostrare nel template postmortem, così come nelle librerie di terze parti, come Django Debug Toolbar.

I motori personalizzati possono fornire la propria informazione template.origin creando un oggetto che specifica i seguenti attributi:

  • 'name': il percorso completo verso il template.
  • 'template_name': il percorso relativo verso il template così come viene passato nei metodi di caricamento del template.
  • 'loader_name': una stringa opzionale che indentifica la funzione o la classe utilizzata per caricare il template, per es. django.template.loaders.filesystem.Loader.
Back to Top