@@ -69,6 +69,16 @@ 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+ # Hold a series of seen dictionaries within Contexts. A dictionary is
74+ # considered seen if it is `in` this list, requiring that the __eq__
75+ # for the dictionary matches. If *anything* in the dictionary is
76+ # different it is counted as a new layer.
77+ self .seen_layers = []
78+ # Holds all dictionaries which have been prettified for output.
79+ # This should align with the seen_layers such that an index here is
80+ # the same as the index there.
81+ self .pformat_layers = []
7282
7383 def _store_template_info (self , sender , ** kwargs ):
7484 template , context = kwargs ['template' ], kwargs ['context' ]
@@ -80,47 +90,66 @@ def _store_template_info(self, sender, **kwargs):
8090
8191 context_list = []
8292 for context_layer in context .dicts :
83- temp_layer = {}
84- if hasattr (context_layer , 'items' ):
85- for key , value in context_layer .items ():
86- # Replace any request elements - they have a large
87- # unicode representation and the request data is
88- # already made available from the Request panel.
89- if isinstance (value , http .HttpRequest ):
90- temp_layer [key ] = '<<request>>'
91- # Replace the debugging sql_queries element. The SQL
92- # data is already made available from the SQL panel.
93- elif key == 'sql_queries' and isinstance (value , list ):
94- temp_layer [key ] = '<<sql_queries>>'
95- # Replace LANGUAGES, which is available in i18n context processor
96- elif key == 'LANGUAGES' and isinstance (value , tuple ):
97- temp_layer [key ] = '<<languages>>'
98- # QuerySet would trigger the database: user can run the query from SQL Panel
99- elif isinstance (value , (QuerySet , RawQuerySet )):
100- model_name = "%s.%s" % (
101- value .model ._meta .app_label , value .model .__name__ )
102- temp_layer [key ] = '<<%s of %s>>' % (
103- value .__class__ .__name__ .lower (), model_name )
104- else :
105- try :
106- recording (False )
107- pformat (value ) # this MAY trigger a db query
108- except SQLQueryTriggered :
109- temp_layer [key ] = '<<triggers database query>>'
110- except UnicodeEncodeError :
111- temp_layer [key ] = '<<unicode encode error>>'
112- except Exception :
113- temp_layer [key ] = '<<unhandled exception>>'
93+ if hasattr (context_layer , 'items' ) and context_layer :
94+ # Refs GitHub issue #910
95+ # If we can find this layer in our pseudo-cache then find the
96+ # matching prettified version in the associated list.
97+ key_values = sorted (context_layer .items ())
98+ if key_values in self .seen_layers :
99+ index = self .seen_layers .index (key_values )
100+ pformatted = self .pformat_layers [index ]
101+ context_list .append (pformatted )
102+ else :
103+ temp_layer = {}
104+ for key , value in context_layer .items ():
105+ # Replace any request elements - they have a large
106+ # unicode representation and the request data is
107+ # already made available from the Request panel.
108+ if isinstance (value , http .HttpRequest ):
109+ temp_layer [key ] = '<<request>>'
110+ # Replace the debugging sql_queries element. The SQL
111+ # data is already made available from the SQL panel.
112+ elif key == 'sql_queries' and isinstance (value , list ):
113+ temp_layer [key ] = '<<sql_queries>>'
114+ # Replace LANGUAGES, which is available in i18n context processor
115+ elif key == 'LANGUAGES' and isinstance (value , tuple ):
116+ temp_layer [key ] = '<<languages>>'
117+ # QuerySet would trigger the database: user can run the query from SQL Panel
118+ elif isinstance (value , (QuerySet , RawQuerySet )):
119+ model_name = "%s.%s" % (
120+ value .model ._meta .app_label , value .model .__name__ )
121+ temp_layer [key ] = '<<%s of %s>>' % (
122+ value .__class__ .__name__ .lower (), model_name )
114123 else :
115- temp_layer [key ] = value
116- finally :
117- recording (True )
118- try :
119- context_list .append (pformat (temp_layer ))
120- except UnicodeEncodeError :
121- pass
122-
123- kwargs ['context' ] = [force_text (item ) for item in context_list ]
124+ try :
125+ recording (False )
126+ force_text (value ) # this MAY trigger a db query
127+ except SQLQueryTriggered :
128+ temp_layer [key ] = '<<triggers database query>>'
129+ except UnicodeEncodeError :
130+ temp_layer [key ] = '<<unicode encode error>>'
131+ except Exception :
132+ temp_layer [key ] = '<<unhandled exception>>'
133+ else :
134+ temp_layer [key ] = value
135+ finally :
136+ recording (True )
137+ # Refs GitHub issue #910
138+ # If we've not seen the layer before then we will add it
139+ # so that if we see it again we can skip formatting it.
140+ self .seen_layers .append (key_values )
141+ # Note: this *ought* to be len(...) - 1 but let's be safe.
142+ index = self .seen_layers .index (key_values )
143+ try :
144+ pformatted = force_text (pformat (temp_layer ))
145+ except UnicodeEncodeError :
146+ pass
147+ else :
148+ # Note: this *ought* to be len(...) - 1 but let's be safe.
149+ self .pformat_layers .insert (index , pformatted )
150+ context_list .append (pformatted )
151+
152+ kwargs ['context' ] = context_list
124153 kwargs ['context_processors' ] = getattr (context , 'context_processors' , None )
125154 self .templates .append (kwargs )
126155
0 commit comments