Lazy functions in Django [Functional programming]
I love to write functions instead of classes. However, Django does not allow us to call functions inside templates.
Sometimes we want to postpone the function calls in templates because they might be expensive. Thus we might want to call them inside the template’s cache fragment or inside an if
statement.
My way around them is to use a lazy_cache
function to postpone and cache a function's result.
Thus the whole usage is something like this:
import datetime as dt
from utilities.functional import lazy_cached
def expensive_computation(result_date, page_number=1):
# do some expensive stuff
return results
def latest_results(request):
result_date = dt.datetime.today()
page_number = request.GET.get('page')
results = lazy_cached(
expensive_computation,
result_date,
page_number=request.GET,
)
return render(
request,
"latest-results.html",
{
"results": results,
"page_number": page_number,
},
)
In templates we can now do:
{% load cache %}
{% block content %}
{% cache 30000 results_page page_number %}
{% for result in results %}
<div>{ { result.name }}</div>
{% endfor %}
{% endcache %}
My recipe for lazy_cached function is:
def lazy_cached(func, *args, **kwargs):
state = {"value": None, "realized?": False}
def wrap():
if state["realized?"]:
return state["value"]
state["value"] = func(*args, **kwargs)
state["realized?"] = True
return state["value"]
return wrap