Низкая производительность при расчете средних

Мне нужно показать средние цены предложения. Проблема в том, что мне нужно вычислить средние значения для комбинаций поля многие ко многим. Я также должен пейджировать все это.

Я уже сделал это. Проблема в том, что у него плохая производительность, и я ищу способ решить эту проблему.

Модель выглядит так:

class Offer(models.Model):
    price = DecimalField(max_digits=10, decimal_places=2)
    quantity = PositiveIntegerField()
    product = ForeignKey(Product)
    qualifiers = ManyToManyField(Qualifier)

Соответствующий код для расчета средних значений таков:

def get_average(product, qualifiers, users=None):
    offers = Offer.objects.filter(product=product)

    if users is not None:
        offers = offers.filter(user__in=users)

    for qualifier in qualifiers:
        offers = offers.filter(qualifiers=qualifier)

    if not offers.count():
        return None

    offers = offers.aggregate(
        quantity_x_price_sum=Sum(F('quantity') * F('price'), output_field=FloatField()),
        quantity_total=Sum('quantity')
    )

    # Weighted average
    return offers['quantity_x_price_sum'] / offers['quantity_total']


def get_averages(product, limit=20, users=None):
    averages = []

    colors = product.qualifiers.filter(type=1)
    sizes = product.qualifiers.filter(type=2)
    other = product.qualifiers.filter(type=3)

    qualifiers = [colors, sizes, other]
    combinations = itertools.product(*qualifiers)

    for combination in combinations:
        average = get_average(product, combination, users)
        if average is not None:
            averages.append(average)

            if len(averages) == limit:
                return averages

    return averages

Основная проблема в itertools.product(* квалификаторах). Это может генерировать сотни комбинаций. И пока len(Цены) == лимит, он должен перебрать каждый из них и выполнить запрос.

Любая помощь будет приветствоваться. Благодарю.

1 ответ

Почему бы вам просто не выполнить среднюю агрегацию с самими запросами?

Из документации Django:

# Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

https://docs.djangoproject.com/en/1.11/topics/db/aggregation/

РЕДАКТИРОВАТЬ: Есть более сложные способы запросить это, надеюсь, это поможет. Не уверены, как он обрабатывает нечисловые данные.

Другие вопросы по тегам