Django — ВЫБЕРИТЕ строку с наибольшей СУММОЙ связанных дочерних элементов, СГРУППИРУЙТЕ ПО связанному родительскому элементу

#python #django #postgresql #distinct #annotate

#python #django #postgresql #различное #аннотировать

Вопрос:

У меня есть три модели, определенные следующим образом:

 class Match(models.Model):
    id = models.IntegerField()

class Market(models.Model):
    match = models.ForeignKey(Match,on_delete=models.CASCADE)

class Issue(models.Model):
    market = models.ForeignKey(Market,related_name='issues',on_delete=models.CASCADE)
    volume = models.PositiveIntegerField()
 

Он структурирован следующим образом:

У каждого Match есть несколько Market , и у каждого Market есть несколько Issue .

Что я хочу сделать: для каждого совпадения выберите рынок с наибольшей суммой выпуска.объем

Это может показаться довольно простым, но я не могу в этом разобраться…

Что я сделал до сих пор:

  1. Без DISTINCT Match условия
 Market.objects.annotate(total_volume=Sum('issues__volume')).order_by("-total_volume")
 

Это работает, как и ожидалось, но Match в моем наборе запросов один раз встречается несколько раз.

  1. Сначала попробуйте выполнить DISTINCT Match условие

Затем я пытаюсь добавить DISTINCT(Match) . Поскольку я использую Postgresql, я могу использовать distinct('match_id') :

 Market.objects.annotate(total_volume=Sum('issues__volume')).order_by("match","-total_volume").distinct("match_id")
 

Но это вызывает следующую ошибку:
NotImplementedError: annotate() distinct(fields) is not implemented.

  1. Вторая попытка с DISTINCT Match условием

Я добился того, чего ожидал, используя:

 Market.objects.values('match_id').annotate(total_volume=Sum('issues__volume')).order_by("-total_volume")
 

Тем не менее, я хочу получить доступ к каждому Issue , связанному с конкретным Market , что здесь невозможно из-за использования values() .

Есть ли у вас какие-либо идеи о том, как заставить его работать с как можно меньшим количеством запросов?

Спасибо за вашу помощь!

Ответ №1:

Хорошо,

Похоже, что он работает, прибегая к подзапросу:

 l = Market.objects.filter(id=OuterRef('pk')).annotate(vol=Sum('issues__volume'))

Market.objects.annotate(total_volume=Subquery(l.values('vol')[:1])).order_by("match_id","-total_volume").distinct("match")
 

Это может предотвратить ошибку NotImplementedError: annotate() distinct(fields) not implemented , но я не могу точно знать, почему!