9d0388efa89ab28bb4c3151105a2d65351b7d7c8
[toast/alpenzoo.git] / django_template_backend_genshi / __init__.py
1 """Genshi Engine for Django 1.8
2
3 The following context variable are already pre-configured and usable:
4     'static'     # staticfiles_storage.url
5     'url'        # reverse
6     'request'    # request
7     'csrf_input' # csrf_input_lazy(request)
8     'csrf_token' # csrf_token_lazy(request)
9
10
11 Usage/configuration:
12     In your settings.py, change the TEMPLATE section to the following:
13
14     TEMPLATES = [
15         {
16             'BACKEND': 'django_template_backend_genshi.GenshiEngine',
17             'DIRS': [],
18             'APP_DIRS': True,
19             'OPTIONS': {
20                 'auto_reload': True,
21                 'app_dirname': 'templates',
22                 'serialization': 'xhtml',
23             },
24         },
25     ]
26
27
28 Questions with answers:
29     How do I add additional context variables or functions that are available to every template?
30
31         Define a receiver function of the signal template_render and add context variables:
32
33         from django.dispatch import receiver
34         from django_template_backend_genshi import template_render
35
36         @receiver(template_render)
37         def add_render_globals(sender, **kwargs):
38             genshi_context = kwargs['genshi_context']
39             request = genshi_context['request']
40             genshi_context['mynewvar'] = len(request)
41 """
42
43 from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
44 import django.template.backends.base
45 import django.dispatch
46 from django.core.urlresolvers import reverse
47 from django.contrib.staticfiles.storage import staticfiles_storage
48 import genshi.template
49 import genshi.template.loader
50 import genshi.template.base
51
52
53 class GenshiEngine(django.template.backends.base.BaseEngine):
54     app_dirname = 'genshi'
55
56     def __init__(self, params):
57         params = params.copy()
58         options = params.pop('OPTIONS').copy()
59         self.app_dirname = options.get('app_dirname', self.app_dirname)
60         super(GenshiEngine, self).__init__(params)
61         loader = genshi.template.TemplateLoader(self.template_dirs, auto_reload=options['auto_reload'])
62         self.loader = loader
63         self.serialization = options.get('serialization', 'xhtml')
64
65     def from_string(self, template_code):
66         try:
67             template = genshi.template.MarkupTemplate(template_code)
68             return GenshiTemplateWrapper(template, self.serialization)
69         except genshi.template.base.TemplateSyntaxError as exc:
70             raise django.template.TemplateSyntaxError(exc.args)
71
72     def get_template(self, template_name):
73         try:
74             template = self.loader.load(template_name)
75             return GenshiTemplateWrapper(template, self.serialization)
76         except genshi.template.loader.TemplateNotFound as exc:
77             raise django.template.TemplateDoesNotExist(exc.args)
78         except genshi.template.base.TemplateSyntaxError as exc:
79             raise django.template.TemplateSyntaxError(exc.args)
80
81
82 # signal emitted just before the template is rendered by GenshiTemplateWrapper to have an opportunity to add
83 # context variables. genshi_context is the Genshi context (genshi.template.base.Context()) already filles with
84 # 'static' and 'url' and - if it's a request - 'request', 'csrf_input' and 'csrf_token'.
85 template_render = django.dispatch.Signal(providing_args=["genshi_context"])
86
87
88 class GenshiTemplateWrapper(object):
89     def __init__(self, template, serialization):
90         self.template = template
91         self.serialization = serialization
92
93     def render(self, context=None, request=None):
94         genshi_context = genshi.template.base.Context()
95         genshi_context['static'] = staticfiles_storage.url
96         genshi_context['url'] = reverse
97         if request is not None:
98             genshi_context['request'] = request
99             genshi_context['csrf_input'] = csrf_input_lazy(request)
100             genshi_context['csrf_token'] = csrf_token_lazy(request)
101         if context is not None:
102             genshi_context.push(context)
103         template_render.send(self, genshi_context=genshi_context)
104         stream = self.template.generate(genshi_context)
105         # this might raise a genshi.template.eval.UndefinedError (derived from genshi.template.base.TemplateRuntimeError)
106         return stream.render(self.serialization)