Во первых не надо ничего кешировать и оптимизировать пока не выяснишь, что тормозит.
В дебуг тулбаре смотри нет ли из этих 150 кучи одинаковых запросов. Большая вероятность, что с помощью select_related и prefetch_related можно сократить количество запросов многократно.
Самый примитивный способ с помощью функции time() змерить сколько выполняются те или иные участки.
Вот такой декоратор (см. ниже), оберни им код любой функции и видно будет, что тормозит.
Единственно, хочу отметить, что если ты передаешь в шаблоны queryset, не преобразовав его в список, то фактически выполнение запроса будет происходить в шаблоне и такой код покажет, что тормозита render, хотя тормозят запросы.
from decorator import decorator
from line_profiler import LineProfiler
@decorator
def profile_each_line(func, *args, **kwargs):
profiler = LineProfiler()
profiled_func = profiler(func)
try:
return profiled_func(*args, **kwargs)
finally:
profiler.print_stats()