Skip to content

Commit 3a18bff

Browse files
committed
Refs django-commons#910 - After Django introduced template based widget rendering, the number of context values which need prettifying has increased drastically, which can (given enough template contexts to render) cause pages using the template panel to become essentially unresponsive due to the sheer amount of data.
Instead, when first seeing a new context layer, attempt to render it as a string (a key) and store that + the pretty output (the value) into a dictionary, and when subsequently seeing the same string (ie: individual iterations of a Select widget) key, use the existing pretty output instead of re-rendering it. This cuts the number of pformat calls at a minimum by half, and ultimately (far) more than that due to re-use of the same one where possible.
1 parent e02f132 commit 3a18bff

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

debug_toolbar/panels/templates/panel.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ class TemplatesPanel(Panel):
6969
def __init__(self, *args, **kwargs):
7070
super(TemplatesPanel, self).__init__(*args, **kwargs)
7171
self.templates = []
72+
# Refs GitHub issue #910
73+
# Holds a collection of unique context layers, keyed by a string
74+
# version of them, with the value holding the `pformat` output
75+
# of the original dictionary. See _store_template_info.
76+
self.pformats = {}
7277

7378
def _store_template_info(self, sender, **kwargs):
7479
template, context = kwargs['template'], kwargs['context']
@@ -104,7 +109,7 @@ def _store_template_info(self, sender, **kwargs):
104109
else:
105110
try:
106111
recording(False)
107-
pformat(value) # this MAY trigger a db query
112+
force_text(value) # this MAY trigger a db query
108113
except SQLQueryTriggered:
109114
temp_layer[key] = '<<triggers database query>>'
110115
except UnicodeEncodeError:
@@ -115,12 +120,28 @@ def _store_template_info(self, sender, **kwargs):
115120
temp_layer[key] = value
116121
finally:
117122
recording(True)
123+
# Refs GitHub issue #910
124+
# After Django introduced template based form widget rendering,
125+
# djdt has to collect and format far more contexts, many of which
126+
# are duplicates, and don't need formatting if we've already seen
127+
# the exact same context.
128+
# We sort the `temp_layer` dictionary as a 2-tuple to ensure that
129+
# ordering is consistent, before simply converting it to a string
130+
# representation to ensure UnicodeEncodeError can be raised as it
131+
# was previously.
132+
# If the stringification succeeded, and we've not seen the key
133+
# before, pformat it. If we've seen it before, we should be able
134+
# to just re-use it.
118135
try:
119-
context_list.append(pformat(temp_layer))
136+
forced = force_text(sorted(temp_layer.items()))
120137
except UnicodeEncodeError:
121-
pass
138+
continue
139+
else:
140+
if forced not in self.pformats:
141+
self.pformats[forced] = force_text(pformat(temp_layer))
142+
context_list.append(self.pformats[forced])
122143

123-
kwargs['context'] = [force_text(item) for item in context_list]
144+
kwargs['context'] = context_list
124145
kwargs['context_processors'] = getattr(context, 'context_processors', None)
125146
self.templates.append(kwargs)
126147

0 commit comments

Comments
 (0)