Задать вопрос
O_godo
@O_godo

Как оптимизировать запрос Django?

Добрый день! Есть следующие модели:

class Product(CreationModificationDateMixin, MetaTagsMixin, ImageThumbnailMixin):
  ...
  brand = models.ForeignKey(
    Brand,
    null=True,
    blank=True,
    related_name='products',
    verbose_name='Производитель',
    on_delete=models.SET_NULL
  )

  material = models.ForeignKey(
    Material,
    verbose_name='Материал',
    blank=True,
    null=True,
    related_name='products',
    on_delete=models.SET_NULL
  )

class Material(models.Model):
  name = models.CharField(
    'Название',
    max_length=100
  )

class Brand(CreationModificationDateMixin, MetaTagsMixin):
  country = models.ForeignKey(
    Country,
    blank=True,
    null=True,
    verbose_name='Страна производителя',
    related_name='brands',
    on_delete=models.SET_NULL
  )

  name = models.CharField(
    'Название бренда',
    max_length=100,
  )

class Country(models.Model):
  name = models.CharField(
    'Название',
    max_length=200
  )


Задание: вывести странны, потом в странах вывести бренды группирируемые по материалам. Пример ниже:
5ab6b4be99424617437460.png

Сделать то я сделал, но прошелся профайлером и вполне ожидаемо получил кучу однотипных запросов. Делал так:
countries = Country.objects.all()
    materials = Material.objects.all()
    country_materials = []

    for country in countries:
        dc = {'country': country, 'materials': []}

        for material in materials:
            brands = Brand.objects.filter(
                products__material=material, country=country).distinct()

            if brands.exists():
                dc['materials'].append({'material': material, 'brands': brands})

        if dc['materials']:
            country_materials.append(dc)

    return {
        'menu': menu,
        'country_materials': country_materials
    }


Проблема еще в том, что меню такое выводится на всех страницах.

Пробовал достучаться через prefetch_related, но не вышло: пробовал так ```Brand.objects.prefetch_related('products__material')``` но получаю товары, а надо как я понимаю, чтоб материалы. Как можно оптимизировать или изменить подход к построению запроса, чтоб в базу не ходили куча запросов?
  • Вопрос задан
  • 259 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
@deliro
Просто убери циклы и сделай один запрос:
brands = Brand.objects.filter(
    products__material__in=materials, 
    country__in=countries
).distinct()
Ответ написан
DMGarikk
@DMGarikk
Lead Software Developer
я после пары месяцев подобных мучений переписал все запросы на raw sql без использования джанговского orm, там где нужно выводить много связанных данных он генерит адовое количество селектов (да еще и с опцией no_cache) и очень сильно тормозит
Ответ написан
Ваш ответ на вопрос

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

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