##########################################
# 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)
"""