After reading this document about thread safety, I am left feeling that there is something missing in the documentation, or my reading of it, or my reasoning.
Let's give a simple example:
class HelloWorldNode(template.Node):
def render(self, context):
return "O HAI LOL"
@register.tag(name="hello_world")
def hello_world(parser, tokens):
"""
Greets the world with wide-eyed awe.
"""
return HelloWorldNode()
I understood this code to construct a new instance of the HelloWorldNode
class whenever the hello_world
tag is used. Other examples involve passing arguments to the constructor, like this:
class HelloWorldNode(template.Node):
def __init__(self, message):
self.message = message
def render(self, context):
return "O HAI LOL " + message
@register.tag(name="hello_world")
def hello_world(parser, tokens):
"""
Greets the world with wide-eyed awe.
"""
message = tokens.split_contents()[1]
return HelloWorldNode(message)
Thus, when hello_world
is executed, a new instance of HelloWorldNode is created, and the instance dictionary has an attribute message
. This instance surely must be used only for the rendering of only the given instance of the tag, as using it for other renderings would mean that the data bound to it would be incorrect. If this were not the case, the arguments would get mixed up between different uses of the tag.
Looking at other examples from the docs, here's a simplified example from here:
def do_current_time(parser, token):
tag_name, format_string = token.split_contents()
return CurrentTimeNode(format_string[1:-1])
As this takes data from the tokens passed to the function, the only way that CurrentTimeNode can work is that a new one is instantiated each time do_current_time
is invoked.
Back to the documentation page, where the dissonance sets in. This is 'bad'.
class CycleNode(Node):
def __init__(self, cyclevars):
self.cycle_iter = itertools.cycle(cyclevars)
def render(self, context):
return self.cycle_iter.next()
The doc says that two pages using the same tag might then experience race conditions if they both use the same node. I don't understand how two templates' rendering could end up sharing the same instance if they both independently instantiate their own.
The way to solve this, says the docs is like this:
class CycleNode(Node):
def __init__(self, cyclevars):
self.cyclevars = cyclevars
def render(self, context):
if self not in context.render_context:
context.render_context[self] = itertools.cycle(self.cyclevars)
cycle_iter = context.render_context[self]
return cycle_iter.next()
This appears to index context.render_context
with self
. The implication of that must be that self
is used to identify the instance in one of two ways:
self
references one specific instance of the class in the whole systemself
references that class only, and in order to reference the instance a render context is requiredIf 1 is true, why not just associate data with self
?
If 2 is true, and the render context is "associated with the context of the template that is currently being rendered", how is it possible to distinguish between two instance of the template tag on the same page?
Is the Node instantiated individually each time the tag is invoked? If so, why the concurrency problems? If not, why not?
The template tags are a way of telling Django that here comes something else than plain HTML. The template tags allows us to to do some programming on the server before sending HTML to the client.
{% include %} Processes a partial template. Any variables in the parent template will be available in the partial template. Variables set from the partial template using the set or assign tags will be available in the parent template.
This flag tells Django that if a “safe” string is passed into your filter, the result will still be “safe” and if a non-safe string is passed in, Django will automatically escape it, if necessary. You can think of this as meaning “this filter is safe – it doesn't introduce any possibility of unsafe HTML.”
Create a custom template tagUnder the application directory, create the templatetags package (it should contain the __init__.py file). For example, Django/DjangoApp/templatetags. In the templatetags package, create a . py file, for example my_custom_tags, and add some code to it to declare a custom tag.
Got it with closer reading of this.
The template is compiled when it is loaded. Any arguments passed into the tag function are 'static'. They are either literal strings, or they are strings which are used as identifiers to look up bound variables in the render context.
Therefore the Node object is instantiated for each tag, and hangs around ready for use whenever the template is used (and naturally the template may be used in any number of threads).
Thus the self
in my question is the identity of the specific Node within the template. Combined with the render context, this gives a unique identity on which to hang instance variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With