Fixed #32824 -- Improved performance of NodeList.render().

This avoids the following:
 - checking that each item in the nodelist is a subclass of Node,
 - calling str() on the render_annotated() output, because it's
   documented that Node.render() must return a string,
 - calling mark_safe() on the output, when the value to be wrapped is
   definitively known to be a string because the result of ''.join()
   is always of that type,
 - using an intermediate list to store each individual string.
This commit is contained in:
Keryn Knight 2021-06-07 12:56:50 +01:00 committed by Mariusz Felisiak
parent 2dfc1066a0
commit 854e9b0668
3 changed files with 9 additions and 10 deletions

View File

@ -59,7 +59,7 @@ from django.template.context import BaseContext
from django.utils.formats import localize from django.utils.formats import localize
from django.utils.html import conditional_escape, escape from django.utils.html import conditional_escape, escape
from django.utils.regex_helper import _lazy_re_compile from django.utils.regex_helper import _lazy_re_compile
from django.utils.safestring import SafeData, mark_safe from django.utils.safestring import SafeData, SafeString, mark_safe
from django.utils.text import ( from django.utils.text import (
get_text_list, smart_split, unescape_string_literal, get_text_list, smart_split, unescape_string_literal,
) )
@ -954,14 +954,9 @@ class NodeList(list):
contains_nontext = False contains_nontext = False
def render(self, context): def render(self, context):
bits = [] return SafeString(''.join([
for node in self: node.render_annotated(context) for node in self
if isinstance(node, Node): ]))
bit = node.render_annotated(context)
else:
bit = node
bits.append(str(bit))
return mark_safe(''.join(bits))
def get_nodes_by_type(self, nodetype): def get_nodes_by_type(self, nodetype):
"Return a list of all nodes of the given type" "Return a list of all nodes of the given type"

View File

@ -463,6 +463,10 @@ Miscellaneous
:class:`~django.utils.feedgenerator.Atom1Feed`, and their subclasses now :class:`~django.utils.feedgenerator.Atom1Feed`, and their subclasses now
emit elements with no content as self-closing tags. emit elements with no content as self-closing tags.
* ``NodeList.render()`` no longer casts the output of ``render()`` method for
individual nodes to a string. ``Node.render()`` should always return a string
as documented.
.. _deprecated-features-4.0: .. _deprecated-features-4.0:
Features deprecated in 4.0 Features deprecated in 4.0

View File

@ -198,4 +198,4 @@ class CounterNode(template.Node):
def render(self, context): def render(self, context):
count = self.count count = self.count
self.count = count + 1 self.count = count + 1
return count return str(count)