There are times when you want to hook into the Variable class of django.template to get extra debugging, or even to change its behavior. The code shown is working code that does just that. You can monkeypatch template variable resolution by calling patch_resolver(). I recommend using it for automated tests at first.
My particular version of _resolve_lookup does two things--it provides some simple tracing, and it also simplifies variable resolution. In particular, I do not allow index lookups on lists, since we never use that feature in our codebase, and I do not silently catch so many exceptions as the original version, since we want to err on the side of failure for tests. (If you want to do monkeypatching in production, you obviously want to be confident in your tests and have good error catching.)
As far as tracing is concerned, right now I am doing very basic "print" statements, but once you have these hooks in place, you can do more exotic things like warn when the same object is being dereferenced too many times, or even build up a graph of object interrelationships. (I leave that as an exercise to the reader.)
If you want to see what the core _resolve_lookup method looks like, you can find it in django/templates/init.py in your installation, or also here (scroll down to line 701 or so):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from django.template import Variable
def patch_resolver():
Variable._resolve_lookup = our_resolver
def our_resolver(self, context):
current = context
how_resolved_steps = []
for bit in self.lookups:
how_resolved, current = resolve_bit(current, bit)
how_resolved_steps.append((how_resolved, current))
debug(self.lookups, how_resolved_steps)
return current
def resolve_bit(current, bit):
# Strict, does not allow list lookups, for example
try:
return 'dictionary', current[bit]
except (TypeError, AttributeError, KeyError):
pass
current = getattr(current, bit)
if not callable(current):
return 'attribute', current
if getattr(current, 'alters_data', False):
raise Exception('trying to alter data')
return 'called attribute', current()
def debug(lookups, how_resolved_steps):
name = 'context'
for i, (how_resolved, value) in enumerate(how_resolved_steps):
bit = lookups[i]
if how_resolved == 'dictionary':
name += "['%s']" % bit
elif how_resolved == 'attribute':
name += '.%s' % bit
else:
name += '.%s()' % bit
print '%.40s' % name, value
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.