########################################## # WARNING! MONKEYPATCHES AHEAD! WARNING! # ########################################## """ There are several changes I have made over time to the core Django code. Some of these fix bugs/inconsistencies in the core code and some are to add functionality. Unfortunately, there are a few changes that I do not know how to make with a Monkey Patch. These require direct modification of the core code and are enumerated at the end of this file. """ ####################################################################### # This should be a relatively safe MonkeyPatch because it only adds # new functionality on top of the most basic calls in the class. # If this breaks, then the BaseCache class must have morphed into Godzilla. # # The following adds a function to Django's BaseCache class # 'name' is the normal cache element name. # 'expr' is a string containing an expression eval-able in the # caller's scope. # # If 'name' is not currently in the cache, the expression is # eval-ed and the results saved under that name. # The cached element is returned. ####################################################################### def add_cache_get_or_eval(): import sys from django.core.cache.backends.base import BaseCache def cache_get_or_eval(self, name, expr, timeout=None): val = self.get(name) if val is None: caller = sys._getframe(1) # use caller's scope val = eval(expr, caller.f_locals, caller.f_globals) self.set(name, val, timeout) return val # cache_or_eval BaseCache.get_or_eval = cache_get_or_eval # add_cache_get_or_eval() add_cache_get_or_eval() ####################################################################### # The template variable evaluation does not check for # call-ability on a simple variable, only on an object # method or list/dict element. # # I.e. if class Foo has method bar, then {{some_foo.bar}} # will call bar on some_foo and use the result. # OTOH, if mumble is a procedure, then {{mumble}} does NOT # do the obvious thing, but instead returns a meaningless # Python function object. # # This patch fixes this behavior (although it could use some work). ####################################################################### def fix_resolve_lookup(): from django.template import Variable from django.conf import settings old_resolve_lookup = Variable._resolve_lookup def new_resolve_lookup(self, context): current = old_resolve_lookup(self, context) if callable(current): try: # call function (assuming no args required) current = current() except TypeError: # arguments *were* required # GOTCHA: This will also catch any TypeError # raised in the function itself. current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call except Exception, e: if getattr(e, 'silent_variable_failure', False): current = settings.TEMPLATE_STRING_IF_INVALID else: raise return current # new_resolve_lookup Variable._resolve_lookup = new_resolve_lookup # fix_resolve_lookup fix_resolve_lookup() ############################################################ # The following cannot be easily monkeypatched and so # requires direct modification of the core code. ############################################################ """ # Show IP in log message from development server # core/servers/basehttp.py ~ 614 in WSGIRequestHandler.log_message() # change this msg = "[%s] %s\n" % (self.log_date_time_string(), format % args) # to this msg = "[%s] %s %s\n" % (self.log_date_time_string(), self.client_address[0], format % args) """