Changes from Winterrodeln (add user defined context variables; render in xhtml).
authorPhilipp Spitzer <philipp@spitzer.priv.at>
Tue, 16 Jun 2015 18:27:54 +0000 (20:27 +0200)
committerPhilipp Spitzer <philipp@spitzer.priv.at>
Tue, 16 Jun 2015 18:27:54 +0000 (20:27 +0200)
django_template_backend_genshi/__init__.py

index 85c338f3a4a2ecdee739554eec11c0e278203a31..9d0388efa89ab28bb4c3151105a2d65351b7d7c8 100644 (file)
@@ -1,5 +1,50 @@
+"""Genshi Engine for Django 1.8
+
+The following context variable are already pre-configured and usable:
+    'static'     # staticfiles_storage.url
+    'url'        # reverse
+    'request'    # request
+    'csrf_input' # csrf_input_lazy(request)
+    'csrf_token' # csrf_token_lazy(request)
+
+
+Usage/configuration:
+    In your settings.py, change the TEMPLATE section to the following:
+
+    TEMPLATES = [
+        {
+            'BACKEND': 'django_template_backend_genshi.GenshiEngine',
+            'DIRS': [],
+            'APP_DIRS': True,
+            'OPTIONS': {
+                'auto_reload': True,
+                'app_dirname': 'templates',
+                'serialization': 'xhtml',
+            },
+        },
+    ]
+
+
+Questions with answers:
+    How do I add additional context variables or functions that are available to every template?
+
+        Define a receiver function of the signal template_render and add context variables:
+
+        from django.dispatch import receiver
+        from django_template_backend_genshi import template_render
+
+        @receiver(template_render)
+        def add_render_globals(sender, **kwargs):
+            genshi_context = kwargs['genshi_context']
+            request = genshi_context['request']
+            genshi_context['mynewvar'] = len(request)
+"""
+
 from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
 import django.template.backends.base
 from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
 import django.template.backends.base
+import django.dispatch
+from django.core.urlresolvers import reverse
+from django.contrib.staticfiles.storage import staticfiles_storage
 import genshi.template
 import genshi.template.loader
 import genshi.template.base
 import genshi.template
 import genshi.template.loader
 import genshi.template.base
@@ -15,36 +60,47 @@ class GenshiEngine(django.template.backends.base.BaseEngine):
         super(GenshiEngine, self).__init__(params)
         loader = genshi.template.TemplateLoader(self.template_dirs, auto_reload=options['auto_reload'])
         self.loader = loader
         super(GenshiEngine, self).__init__(params)
         loader = genshi.template.TemplateLoader(self.template_dirs, auto_reload=options['auto_reload'])
         self.loader = loader
-
+        self.serialization = options.get('serialization', 'xhtml')
 
     def from_string(self, template_code):
         try:
             template = genshi.template.MarkupTemplate(template_code)
 
     def from_string(self, template_code):
         try:
             template = genshi.template.MarkupTemplate(template_code)
-            return GenshiTemplateWrapper(template)
+            return GenshiTemplateWrapper(template, self.serialization)
         except genshi.template.base.TemplateSyntaxError as exc:
             raise django.template.TemplateSyntaxError(exc.args)
 
         except genshi.template.base.TemplateSyntaxError as exc:
             raise django.template.TemplateSyntaxError(exc.args)
 
-
     def get_template(self, template_name):
         try:
             template = self.loader.load(template_name)
     def get_template(self, template_name):
         try:
             template = self.loader.load(template_name)
-            return GenshiTemplateWrapper(template)
+            return GenshiTemplateWrapper(template, self.serialization)
         except genshi.template.loader.TemplateNotFound as exc:
             raise django.template.TemplateDoesNotExist(exc.args)
         except genshi.template.base.TemplateSyntaxError as exc:
             raise django.template.TemplateSyntaxError(exc.args)
 
 
         except genshi.template.loader.TemplateNotFound as exc:
             raise django.template.TemplateDoesNotExist(exc.args)
         except genshi.template.base.TemplateSyntaxError as exc:
             raise django.template.TemplateSyntaxError(exc.args)
 
 
+# signal emitted just before the template is rendered by GenshiTemplateWrapper to have an opportunity to add
+# context variables. genshi_context is the Genshi context (genshi.template.base.Context()) already filles with
+# 'static' and 'url' and - if it's a request - 'request', 'csrf_input' and 'csrf_token'.
+template_render = django.dispatch.Signal(providing_args=["genshi_context"])
+
+
 class GenshiTemplateWrapper(object):
 class GenshiTemplateWrapper(object):
-    def __init__(self, template):
+    def __init__(self, template, serialization):
         self.template = template
         self.template = template
+        self.serialization = serialization
 
     def render(self, context=None, request=None):
 
     def render(self, context=None, request=None):
-        if context is None:
-            context = {}
+        genshi_context = genshi.template.base.Context()
+        genshi_context['static'] = staticfiles_storage.url
+        genshi_context['url'] = reverse
         if request is not None:
         if request is not None:
-            context['request'] = request
-            context['csrf_input'] = csrf_input_lazy(request)
-            context['csrf_token'] = csrf_token_lazy(request)
-        stream = self.template.generate(**context)
-        return stream.render()
+            genshi_context['request'] = request
+            genshi_context['csrf_input'] = csrf_input_lazy(request)
+            genshi_context['csrf_token'] = csrf_token_lazy(request)
+        if context is not None:
+            genshi_context.push(context)
+        template_render.send(self, genshi_context=genshi_context)
+        stream = self.template.generate(genshi_context)
+        # this might raise a genshi.template.eval.UndefinedError (derived from genshi.template.base.TemplateRuntimeError)
+        return stream.render(self.serialization)