Ответ
Технически да, но это плохая практика для кэширования данных между запросами из-за особенностей жизненного цикла экземпляров View в Django. Однако это приемлемый способ избежать повторных вычислений в рамках одного запроса.
Проблема: Состояние View между запросами
Django может переиспользовать один и тот же экземпляр View для обработки нескольких запросов от разных пользователей. Если вы сохраните данные в атрибуте экземпляра (self.my_data = ...), эти данные могут "протечь" в следующий запрос, что приведет к показу неверной или чужой информации.
Анти-паттерн (не делайте так для межзапросного кэша):
class LeakyView(View):
_cached_data = None # Атрибут будет жить дольше одного запроса
def get(self, request):
if self._cached_data is None:
# Тяжелая операция, выполняется только один раз для экземпляра
self._cached_data = heavy_database_query()
return HttpResponse(self._cached_data)
Правильный подход: Кэширование в рамках одного запроса
Если вам нужно вычислить значение один раз и использовать его в нескольких методах View в течение обработки одного запроса (например, в get_context_data и get), используйте декоратор @cached_property.
from django.utils.functional import cached_property
from django.views.generic import TemplateView
class MyView(TemplateView):
template_name = "my_template.html"
@cached_property
def complex_data(self):
# Эта тяжелая операция выполнится только один раз за запрос
print("Выполняется дорогой запрос...")
return list(MyModel.objects.filter(is_active=True))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['items'] = self.complex_data # Первый вызов
return context
def get(self, request, *args, **kwargs):
# ... какая-то логика
print(f"Количество элементов: {len(self.complex_data)}") # Второй вызов, но запрос не повторится
return super().get(request, *args, **kwargs)
Лучшее решение: Django Cache Framework
Для кэширования данных между запросами всегда используйте встроенный фреймворк кэширования Django. Он безопасен и предоставляет контроль над временем жизни кэша.
from django.core.cache import cache
def get_data_view(request):
data = cache.get('my_unique_cache_key')
if data is None:
data = heavy_database_query()
cache.set('my_unique_cache_key', data, timeout=300) # Кэш на 5 минут
return HttpResponse(data) Ответ 18+ 🔞
О, смотри-ка, какой вопрос подкинули! Технически-то да, можно, но это, блядь, пиздец какая плохая практика, если ты хочешь кэшировать данные между запросами. Потому что жизненный цикл этих View в Django — это отдельный ёперный театр.
В чём, сука, подвох? Состояние View между запросами
Представь себе: Django может взять один и тот же экземпляр твоего View и, как хитрая жопа, подсунуть его для обработки запроса от другого пользователя. И если ты нахрапом запихнул данные в атрибут экземпляра (self.my_data = ...), то эти данные могут, блядь, «протечь» в следующий запрос. И получится, что Вася увидит фотки из отпуска Пети. Пиздец и скандал.
Вот так делать НЕ НАДО, ёпта (анти-паттерн для межзапросного кэша):
class LeakyView(View):
_cached_data = None # Этот атрибут будет жить дольше, чем один запрос, вот в чём засада!
def get(self, request):
if self._cached_data is None:
# Тяжёлая операция, выполнится всего раз для экземпляра... и накроет всех
self._cached_data = heavy_database_query()
return HttpResponse(self._cached_data)
Нормальный подход: Кэш в рамках одного запроса
А вот если тебе надо что-то посчитать один раз и юзать в разных методах в течение одного запроса (ну, там, в get_context_data и ещё где), то тут уже можно. Бери декоратор @cached_property, он твой друг.
from django.utils.functional import cached_property
from django.views.generic import TemplateView
class MyView(TemplateView):
template_name = "my_template.html"
@cached_property
def complex_data(self):
# Эта тяжёлая операция выполнится только один раз за запрос
print("Выполняется дорогой запрос...")
return list(MyModel.objects.filter(is_active=True))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['items'] = self.complex_data # Первый вызов
return context
def get(self, request, *args, **kwargs):
# ... какая-то логика
print(f"Количество элементов: {len(self.complex_data)}") # Второй вызов, но запрос не повторится
return super().get(request, *args, **kwargs)
А если по-взрослому? Django Cache Framework
Для кэширования между запросами — забудь про эти самоделки, блядь. Используй встроенный фреймворк кэширования Django. Он безопасный и даёт контроль над временем жизни кэша, а не как у нас — «авось пронесёт».
from django.core.cache import cache
def get_data_view(request):
data = cache.get('my_unique_cache_key')
if data is None:
data = heavy_database_query()
cache.set('my_unique_cache_key', data, timeout=300) # Кэш на 5 минут
return HttpResponse(data)
Вот так, без выёбок и подводных камней.