Projet

Général

Profil

Télécharger (4,91 ko) Statistiques
| Branche: | Tag: | Révision:

root / entrouvert / djommon / multitenant / template_loader.py @ e4332b43

1
"""
2
Wrapper class that takes a list of template loaders as an argument and attempts
3
to load templates from them in order, caching the result.
4
"""
5

    
6
import hashlib
7
from django.conf import settings
8
from django.core.exceptions import ImproperlyConfigured
9
from django.template.base import TemplateDoesNotExist
10
from django.template.loader import BaseLoader, get_template_from_string, find_template_loader, make_origin
11
from django.utils.encoding import force_bytes
12
from django.utils._os import safe_join
13
from django.db import connection
14

    
15
from . import app_settings
16

    
17
class CachedLoader(BaseLoader):
18
    is_usable = True
19

    
20
    def __init__(self, loaders):
21
        self.template_cache = {}
22
        self._loaders = loaders
23
        self._cached_loaders = []
24

    
25
    @property
26
    def loaders(self):
27
        # Resolve loaders on demand to avoid circular imports
28
        if not self._cached_loaders:
29
            # Set self._cached_loaders atomically. Otherwise, another thread
30
            # could see an incomplete list. See #17303.
31
            cached_loaders = []
32
            for loader in self._loaders:
33
                cached_loaders.append(find_template_loader(loader))
34
            self._cached_loaders = cached_loaders
35
        return self._cached_loaders
36

    
37
    def find_template(self, name, dirs=None):
38
        for loader in self.loaders:
39
            try:
40
                template, display_name = loader(name, dirs)
41
                return (template, make_origin(display_name, loader, name, dirs))
42
            except TemplateDoesNotExist:
43
                pass
44
        raise TemplateDoesNotExist(name)
45

    
46
    def load_template(self, template_name, template_dirs=None):
47
        if connection.tenant:
48
            key = '-'.join([str(connection.tenant.pk), template_name])
49
        else:
50
            key = template_name
51
        if template_dirs:
52
            # If template directories were specified, use a hash to differentiate
53
            if connection.tenant:
54
                key = '-'.join([str(connection.tenant.pk), template_name, hashlib.sha1(force_bytes('|'.join(template_dirs))).hexdigest()])
55
            else:
56
                key = '-'.join([template_name, hashlib.sha1(force_bytes('|'.join(template_dirs))).hexdigest()])
57

    
58
        if key not in self.template_cache:
59
            template, origin = self.find_template(template_name, template_dirs)
60
            if not hasattr(template, 'render'):
61
                try:
62
                    template = get_template_from_string(template, origin, template_name)
63
                except TemplateDoesNotExist:
64
                    # If compiling the template we found raises TemplateDoesNotExist,
65
                    # back off to returning the source and display name for the template
66
                    # we were asked to load. This allows for correct identification (later)
67
                    # of the actual template that does not exist.
68
                    return template, origin
69
            self.template_cache[key] = template
70
        return self.template_cache[key], None
71

    
72
    def reset(self):
73
        "Empty the template cache."
74
        self.template_cache.clear()
75

    
76
class FilesystemLoader(BaseLoader):
77
    is_usable = True
78

    
79
    def get_template_sources(self, template_name, template_dirs=None):
80
        """
81
        Returns the absolute paths to "template_name", when appended to each
82
        directory in "template_dirs". Any paths that don't lie inside one of the
83
        template dirs are excluded from the result set, for security reasons.
84
        """
85
        if not connection.tenant:
86
            return
87
        if not template_dirs:
88
            try:
89
                template_dirs = app_settings.MULTITENANT_TEMPLATE_DIRS
90
            except AttributeError:
91
                raise ImproperlyConfigured('To use %s.%s you must define the MULTITENANT_TEMPLATE_DIRS' % (__name__, FilesystemLoader.__name__))
92
        for template_dir in template_dirs:
93
            try:
94
                yield safe_join(template_dir, connection.tenant.domain_url, template_name)
95
            except UnicodeDecodeError:
96
                # The template dir name was a bytestring that wasn't valid UTF-8.
97
                raise
98
            except ValueError:
99
                # The joined path was located outside of this particular
100
                # template_dir (it might be inside another one, so this isn't
101
                # fatal).
102
                pass
103

    
104
    def load_template_source(self, template_name, template_dirs=None):
105
        tried = []
106
        for filepath in self.get_template_sources(template_name, template_dirs):
107
            try:
108
                with open(filepath, 'rb') as fp:
109
                    return (fp.read().decode(settings.FILE_CHARSET), filepath)
110
            except IOError:
111
                tried.append(filepath)
112
        if tried:
113
            error_msg = "Tried %s" % tried
114
        else:
115
            error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."
116
        raise TemplateDoesNotExist(error_msg)
117
    load_template_source.is_usable = True
(6-6/8)