Skip to content

Commit

Permalink
Workaround 'render_' thread safety issue.
Browse files Browse the repository at this point in the history
  • Loading branch information
idlesign committed Dec 1, 2018
1 parent dc0834d commit f3e7c7d
Showing 1 changed file with 39 additions and 35 deletions.
74 changes: 39 additions & 35 deletions etc/templatetags/etc_misc.py
@@ -1,10 +1,11 @@
from copy import deepcopy
from functools import partial

from django import VERSION
from django import template
from django.template import TemplateDoesNotExist
from django.template.base import UNKNOWN_SOURCE, Lexer, Parser
from django.template.loader_tags import do_include, IncludeNode
from django.template.loader_tags import do_include, Node

try:
from django.template.loader_tags import construct_relative_path
Expand Down Expand Up @@ -43,44 +44,47 @@ def site_url(context):
return get_site_url(request=context.get('request', None))


class DynamicIncludeNode(IncludeNode):
class DynamicIncludeNode(Node):

def __init__(self, *args, **kwargs):
self.fallback = kwargs.pop('fallback', None)
super(DynamicIncludeNode, self).__init__(*args, **kwargs)

if VERSION >= (2, 1, 0):

def render_(self, tpl_new, context):
template = self.template

tpl_old = template.var
template.var = tpl_new

try:
return super(DynamicIncludeNode, self).render(context)
context_key = '__include_context'

finally:
template.var = tpl_old

else:

# Now we need to turn on context.template.engine.debug to raise exception
# as in 2.1+
def render_(self, tpl_new, context):
template = self.template

tpl_old = template.var
template.var = tpl_new
debug_old = context.template.engine.debug
context.template.engine.debug = True
def __init__(self, template, *args, extra_context=None, isolated_context=False, **kwargs):
self.fallback = kwargs.pop('fallback', None)

try:
return super(DynamicIncludeNode, self).render(context)
# Below is implementation from Django 2.1 generic IncludeNode.
self.template = template
self.extra_context = extra_context or {}
self.isolated_context = isolated_context
super(DynamicIncludeNode, self).__init__(*args, **kwargs)

finally:
template.var = tpl_old
context.template.engine.debug = debug_old
def render_(self, tpl_new, context):

template = deepcopy(self.template) # Do not mess with global template for threadsafety.
template.var = tpl_new # Cheat a little

# Below is implementation from Django 2.1 generic IncludeNode.

template = template.resolve(context)
# Does this quack like a Template?
if not callable(getattr(template, 'render', None)):
# If not, try the cache and get_template().
template_name = template
cache = context.render_context.dicts[0].setdefault(self, {})
template = cache.get(template_name)
if template is None:
template = context.template.engine.get_template(template_name)
cache[template_name] = template
# Use the base.Template of a backends.django.Template.
elif hasattr(template, 'template'):
template = template.template
values = {
name: var.resolve(context)
for name, var in self.extra_context.items()
}
if self.isolated_context:
return template.render(context.new(values))
with context.push(**values):
return template.render(context)

def render(self, context):
render_ = self.render_
Expand Down

0 comments on commit f3e7c7d

Please sign in to comment.