From 854e9b066850b9b4eb1171966e996322b2c16d27 Mon Sep 17 00:00:00 2001 From: Keryn Knight Date: Mon, 7 Jun 2021 12:56:50 +0100 Subject: [PATCH] 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. --- django/template/base.py | 13 ++++--------- docs/releases/4.0.txt | 4 ++++ tests/template_tests/templatetags/custom.py | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/django/template/base.py b/django/template/base.py index 1446cc865e..4972bd7c58 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -59,7 +59,7 @@ from django.template.context import BaseContext from django.utils.formats import localize from django.utils.html import conditional_escape, escape 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 ( get_text_list, smart_split, unescape_string_literal, ) @@ -954,14 +954,9 @@ class NodeList(list): contains_nontext = False def render(self, context): - bits = [] - 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)) + return SafeString(''.join([ + node.render_annotated(context) for node in self + ])) def get_nodes_by_type(self, nodetype): "Return a list of all nodes of the given type" diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt index 2bdb76ef3d..a9e660f0f1 100644 --- a/docs/releases/4.0.txt +++ b/docs/releases/4.0.txt @@ -463,6 +463,10 @@ Miscellaneous :class:`~django.utils.feedgenerator.Atom1Feed`, and their subclasses now 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: Features deprecated in 4.0 diff --git a/tests/template_tests/templatetags/custom.py b/tests/template_tests/templatetags/custom.py index da7dd0a878..8efd70147a 100644 --- a/tests/template_tests/templatetags/custom.py +++ b/tests/template_tests/templatetags/custom.py @@ -198,4 +198,4 @@ class CounterNode(template.Node): def render(self, context): count = self.count self.count = count + 1 - return count + return str(count)