Django - как уменьшить количество запросов к БД при итерации - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть модель ProductFilter в проекте. Объект этой модели - это набор поисков, определяющих набор запросов. Это как группа товаров - но как фильтр, не связанный с ForeignKey (ManyToManyField).

Товар может быть отфильтрован за несколько ProductFilter с, и первый учитывается.

Это работает так:

Пользователь определяет свои фильтры. Затем назначьте каждому фильтру некоторые правила ценообразования (и другие). Например, фильтр с именем «Продукты до 10 долларов США» - правило - увеличивает цену на 10% .

Проблема заключается в том, что при рендеринге продуктов или экспорте их. Я должен проверить для каждого продукта, принадлежат ли они к какому-либо фильтру, что означает много запросов к БД. Может быть 100 000 товаров.

У вас есть идеи, как сделать это быстрее?

class Product(...):
    ...
    @property
    def price(self):
        for filter in self.user.filters():
            if filter.get_queryset().filter(pk=self.pk).exists():
                return filter.rule.apply_rule(self.price)


class ProductFilter(BaseTimeStampedModel):
    project = models.ForeignKey('projects.UserEshop', related_name='product_filters', on_delete=models.CASCADE)
    order = models.IntegerField(default=0)
    name = models.CharField(max_length=64)
    categories = models.ManyToManyField('FeedCategory', blank=True)
    brands = models.ManyToManyField('Brand', blank=True)
    manufacturers = models.ManyToManyField('Manufacturer', blank=True)
    import_price_no_vat_max = models.DecimalField(decimal_places=2, max_digits=64, null=True, blank=True)
    import_price_no_vat_min = models.DecimalField(decimal_places=2, max_digits=64, null=True, blank=True)
    name_icontains = models.CharField(max_length=128, null=True, blank=True)


    def get_queryset(self):
         # products for this project
         qs = Product.objects.filter(source__user_eshop=self.project)
        if self.categories.exists():
            qs = qs.filter(category__in=self.categories.all().get_descendants(include_self=True))
        if self.brands.exists():
            qs = qs.filter(brand__in=self.brands.all())
        if self.manufacturers.exists():
            qs = qs.filter(manufacturer__in=self.manufacturers.all())
        if self.import_price_no_vat_max is not None:
            qs = qs.filter(import_price_no_vat__lte=self.import_price_no_vat_max)
        if self.import_price_no_vat_min is not None:
            qs = qs.filter(import_price_no_vat__gte=self.import_price_no_vat_min)
        if self.name_icontains:
            qs = qs.filter(name__icontains=self.name_icontains)
        return qs

РЕДАКТИРОВАТЬ

Моя лучшая идея заключается в том, чтобы создайте ManyToManyField для ProductFilter до Product и каждый раз, когда что-то меняется, я назначаю продукты каждому фильтру. Я просто не уверен, что с ManyToManyField можно хранить тысячи или сотни тысяч товаров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...