@mkone112
Начинающий питонист.

Как упростить агрегацию?

Я очень часто сталкиваюсь с подобными задачами, но до сих пор не понимаю как их правильно решать, пример:
Дана вот такая схема моделей:
635881705f101731469194.jpeg
Задача - вывести 5 клиентов потративших больше всего денег. Каждый клиент описывается следующими полями:
username - логин клиента;
spent_money - сумма потраченных средств за весь период;
gems - список из названий камней, которые купили как минимум двое из списка "5 клиентов, потративших
наибольшую сумму за весь период", и данный клиент является одним из этих покупателей.

Модели:
class Deal(models.Model):
    customer = models.ForeignKey('Customer', on_delete=models.CASCADE, related_name='deals')
    item = models.ForeignKey('Item', on_delete=models.CASCADE, related_name='deals')
    total = models.DecimalField(decimal_places=3, max_digits=10, validators=[MinValueValidator(Decimal('0.0'))])
    quantity = models.PositiveIntegerField()
    created_at = models.DateTimeField(auto_now_add=True)


class Customer(models.Model):
    name = models.TextField()

class Item(models.Model):
    name = models.TextField()


Запрос:
customers_data = list(
    Deal.objects.values(
        'customer__pk',
        'customer__name'
     ).annotate(sum_total=Sum('total')).order_by('-sum_total')[:5]
)

customers_pk = tuple(element['customer__pk'] for element in customers_data)

deals_qs = Deal.objects.filter(customer__pk__in=customers_pk)
items_pk = deals_qs.values(
    'item__pk',
).annotate(
    item_count=Count('customer__pk', distinct=True),
).filter(
    item_count__gte=REPEATED_ITEMS_COUNT,
).values_list('item__pk', flat=True)

repeated_items = deals_qs.filter(
    item__pk__in=items_pk,
).values(
    'customer__pk',
    'item__name',
).order_by(
    'customer__pk',
).distinct()

repeated_items_by_customers = defaultdict(list)

for row in repeated_items:
    customer_pk, item_name = row['customer__pk'], row['item__name']
    repeated_items_by_customers[customer_pk].append(item_name)

result = []
for customer_data in customers_data:
    customer_pk = customer_data['customer__pk']
    result.append(
      [
           customer_data['customer__name'],
           customer_data['sum_total'],
           repeated_items_by_customers[customer_pk],
      ]
 )


Каждый раз я решаю их примерно так. Вопрос - как это сделать правильно?
  • Вопрос задан
  • 106 просмотров
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы