Commit 1acfd624 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Added initial support for loading template engines.

parent b19693e6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -230,6 +230,8 @@ TEMPLATE_CONTEXT_PROCESSORS = (
# Output to use in template system for invalid (e.g. misspelled) variables.
TEMPLATE_STRING_IF_INVALID = ''

TEMPLATES = []

# Default email address to use for various automated correspondence from
# the site managers.
DEFAULT_FROM_EMAIL = 'webmaster@localhost'
+20 −0
Original line number Diff line number Diff line
@@ -53,6 +53,25 @@ MIDDLEWARE_CLASSES = (

ROOT_URLCONF = '{{ project_name }}.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.core.context_processors.debug',
                'django.core.context_processors.i18n',
                'django.core.context_processors.tz',
                'django.core.context_processors.media',
                'django.core.context_processors.static',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = '{{ project_name }}.wsgi.application'


@@ -66,6 +85,7 @@ DATABASES = {
    }
}


# Internationalization
# https://docs.djangoproject.com/en/{{ docs_version }}/topics/i18n/

+13 −1
Original line number Diff line number Diff line
### Multiple Template Engines

from .utils import EngineHandler


engines = EngineHandler()

__all__ = ('engines',)


### Django Template Language

# Public exceptions
from .base import (TemplateDoesNotExist, TemplateSyntaxError,           # NOQA
                   VariableDoesNotExist)
@@ -14,4 +26,4 @@ from .base import resolve_variable # NOQA
from .base import Library                                               # NOQA


__all__ = ('Template', 'Context', 'RequestContext')
__all__ += ('Template', 'Context', 'RequestContext')
+98 −0
Original line number Diff line number Diff line
from collections import Counter, OrderedDict
import os
import sys
import warnings

from django.apps import apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils import lru_cache
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.functional import cached_property
from django.utils.module_loading import import_string


class InvalidTemplateEngineError(ImproperlyConfigured):
    pass


class EngineHandler(object):
    def __init__(self, templates=None):
        """
        templates is an optional list of template engine definitions
        (structured like settings.TEMPLATES).
        """
        self._templates = templates
        self._engines = {}

    @cached_property
    def templates(self):
        if self._templates is None:
            self._templates = settings.TEMPLATES

        if not self._templates:
            warnings.warn(
                "You haven't defined a TEMPLATES setting. You must do so "
                "before upgrading to Django 2.0. Otherwise Django will be "
                "unable to load templates.", RemovedInDjango20Warning)
            self._templates = [
                {
                    'BACKEND': 'django.template.backends.django.DjangoTemplates',
                    'DIRS': settings.TEMPLATE_DIRS,
                    'OPTIONS': {
                        'allowed_include_roots': settings.ALLOWED_INCLUDE_ROOTS,
                        'context_processors': settings.TEMPLATE_CONTEXT_PROCESSORS,
                        'loaders': settings.TEMPLATE_LOADERS,
                        'string_if_invalid': settings.TEMPLATE_STRING_IF_INVALID,
                    },
                },
            ]

        templates = OrderedDict()
        for tpl in self._templates:
            tpl = tpl.copy()
            try:
                # This will raise an exception if 'BACKEND' doesn't exist or
                # isn't a string containing at least one dot.
                default_name = tpl['BACKEND'].rsplit('.', 2)[-2]
            except Exception:
                invalid_backend = tpl.get('BACKEND', '<not defined>')
                raise ImproperlyConfigured(
                    "Invalid BACKEND for a template engine: {}. Check "
                    "your TEMPLATES setting.".format(invalid_backend))

            tpl.setdefault('NAME', default_name)
            tpl.setdefault('DIRS', [])
            tpl.setdefault('APP_DIRS', False)
            tpl.setdefault('OPTIONS', {})

            templates[tpl['NAME']] = tpl

        counts = Counter(list(templates))
        duplicates = [alias for alias, count in counts.most_common() if count > 1]
        if duplicates:
            raise ImproperlyConfigured(
                "Template engine aliases aren't unique, duplicates: {}. "
                "Set a unique NAME for each engine in settings.TEMPLATES."
                .format(", ".join(duplicates)))

        return templates

    def __getitem__(self, alias):
        try:
            return self._engines[alias]
        except KeyError:
            try:
                params = self.templates[alias]
            except KeyError:
                raise InvalidTemplateEngineError(
                    "Could not find config for '{}' "
                    "in settings.TEMPLATES".format(alias))

            backend = params.pop('BACKEND')
            engine_cls = import_string(backend)
            engine = engine_cls(params)

            self._engines[alias] = engine
            return engine

    def __iter__(self):
        return iter(self.templates)

    def all(self):
        return [self[alias] for alias in self]


@lru_cache.lru_cache()
+10 −1
Original line number Diff line number Diff line
@@ -84,8 +84,9 @@ def clear_routers_cache(**kwargs):


@receiver(setting_changed)
def reset_default_template_engine(**kwargs):
def reset_template_engines(**kwargs):
    if kwargs['setting'] in {
        'TEMPLATES',
        'TEMPLATE_DIRS',
        'ALLOWED_INCLUDE_ROOTS',
        'TEMPLATE_CONTEXT_PROCESSORS',
@@ -93,7 +94,15 @@ def reset_default_template_engine(**kwargs):
        'TEMPLATE_LOADERS',
        'TEMPLATE_STRING_IF_INVALID',
        'FILE_CHARSET',
        'INSTALLED_APPS',
    }:
        from django.template import engines
        try:
            del engines.templates
        except AttributeError:
            pass
        engines._templates = None
        engines._engines = {}
        from django.template.engine import Engine
        Engine.get_default.cache_clear()

Loading