Shshzik
@Shshzik
Начинающий

Как использовать prefetch_related в методе модели?

Есть след. модели:

class Product(models.Model):
    name = models.CharField('Наименование', max_length=255)
    
    def main_image(self):
        first_image = self.images.filter(is_main=True).first()
        if first_image is not None:
            i = first_image
        elif self.images.first() is not None:
            i = self.images.first()
        else:
            i = None
        return i

class ProductImage(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
    is_main = models.BooleanField(default=0, verbose_name='Основное')
    image = models.ImageField(upload_to='images', verbose_name='Изображение')


Когда вызываю методе main_image он нормально работает, но генерирует 3-4 обращения в БД. И когда я использую его в шаблоне при 15 товарах, то количество запросов увеличивается пропорционально.
Вопрос - можно ли это как-то оптимизировать? Читал про prefetch_related, но у меня никак не получается им воспользоваться внутри метода.
  • Вопрос задан
  • 632 просмотра
Решения вопроса 1
@deliro
Во-первых, ты сам зачем-то выполняешь 3 запроса в каждом методе непонятно зачем.
def main_image(self):
    return self.images.order_by('-is_main').first()

Сделает один запрос и вернёт ровно тоже самое. В одну строку

Во-вторых, в доке, кажется, достаточно подробно описано, как префетч кастомить:
qs = ProductImage.objects.order_by('-is_main')[:1]
products = Product.objects.prefetch_related(Prefetch('images', queryset=qs, to_attr='covers'))
products.covers.first()

Также можно изменить метод отдачи главной картинки, чтобы он мог работать с префетчеными изображениями
def main_image(self):
    qs = self.images.order_by('-is_main')
    if getattr(self, 'covers', None) is not None:
        qs = self.covers
    return qs.first()
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы