views:

77

answers:

1

Sorry or the confusing title! It's actually a lot simpler than it sounds.

I've got a function:

def get_messages(request):
    # do something expensive with the request
    return 'string'

I want to be able to call that function from the template, so I've strapped in with a context processor:

def context_processor(request):
    return {'messages':get_messages(request)}

So now when I have {{messages}} in my template, string prints out. Great.

The problem is get_messages is quite expensive and isn't always needed. Less than half the templates need it. Is there a way of passing the function to the template and leave it up to the template if it runs or not?

I tried this already:

def context_processor(request):
    return {'messages':get_messages}

But that just outputs the function description <function get_messages at 0x23e97d0> in the template instead of running it.

+2  A: 

I think You shouldn't mix logic of application with template (the view in MVC pattern). This breaks consistency the architecture. You can call get_messages in views that need it and simply pass messages to the template context, in the others just pass None.

But answering Your question: You can make a proxy object. E.g:

class Proxy(object):
    def __init__(self, request)
        self.request = request
        super(Proxy, self).__init__()

    def get_messages(self):
        # so some expensive things
        return 'string'

# context processor
def context_processor(request):
    return {'messages':Proxy(request)}

# in the view
{{ messages.get_messages }}

You can make this ever more generic, and create Proxy class that has one method (e.g get), and takes one parameter in constructor: a function which takes request object as first parameter. This way You gain generic method to proxy a function call in Your templates. Here it is:

class Proxy(object):
    def __init__(self, request, function)
        self.request = request
        self.function = function
        super(Proxy, self).__init__()

    def get(self):
        return self.function(self.request)

then You can write even cooler than I had written before:

# context processor
def context_processor(request):
    return {'messages':Proxy(request, get_messages)}

# sounds nice to me
{{ messages.get }}
Dejw
This solution just occurred to me outside while having a pensive cigarette. Not that I'm taking any credit but just saying, I completely agree; this looks like the best solution available!
Oli