Оптимизация запроса с помощью кэша QuerySet

Я хочу оптимизировать запросы в базу данных. У меня возникает ситуация по которой мне нужно фильтровать по одному столбцу, но по с нескольким значениям. И все отфильтрованные данные отправить в словаре.

Я знаю, что у QuerySet есть кэш. Но похоже в моей ситуации, он не работает или я делаю что-то не так.

Вот упрощенная модель и варианты работы с кэшом QuerySet.

class Meme(models.Model):
    name = models.CharField(max_length=50)


meme = Meme.objects.all()
meme_list = list(meme)  # тут происходит оценивание QuerySet и запись в кэш
print(meme)  # берутся данные из кэша из QuerySet объекта meme
meme_name_list = []
    for i in meme:  # тут тоже берутся данные из кэша из QuerySet объекта meme
        meme_name_list.append(i.name)  

Далее код который мне нужно оптимизировать:

filtered_meme = meme.filter(name__icontains='Иван')  # тут не используется кэш из QuerySet объекта meme, 
                                                # хотя в объекте meme, а значит и в кэше точно есть эти данные. 
filtered_meme1 = meme.filter(name__icontains='Петя')
filtered_meme2 = meme.filter(name__icontains='Саня')
filtered_meme3 = meme.filter(name__icontains='Маша')
filtered_meme4 = meme.filter(name__icontains='Соня')

data = {
    "filtered_meme": filtered_meme,
    "filtered_meme1": filtered_meme1,
    "filtered_meme2": filtered_meme2,
    "filtered_meme3": filtered_meme3,
    "filtered_meme4": filtered_meme4,
}

На каждую такую фильтрацию будет новый запрос в бд.

Можно ли такие запросы как-нибудь оптимизировать с помощью кэша QuerySet? Или какие есть альтернативы решения данной проблемы.

Один хороший человек дал решение:

import functools
from collections import defaultdict
from operator import or_
from django.db.models import Q, Case, CharField, Value, When

values = ("Иван", "Петя", "Саня")
result = defaultdict(list)
queryset = Meme.objects.annotate(
    i=Case(
        *[
            When(
                name__icontains=value,
                then=Value(str(i))
            )
            for i, value in enumerate(values)
        ],
        output_field=CharField()
    )
).filter(
    functools.reduce(
        or_,
        [
            Q(name__icontains=value)
            for value in values
        ]
    )
)
for obj in queryset:
    result["filtered_meme" + (obj.i if obj.i != "0" else "")].append(obj)

Данный подход выполняет один запрос в базу данных.

Вернуться на верх