#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
.
Что я хочу сделать: для каждого совпадения выберите рынок с наибольшей суммой выпуска.объем
Это может показаться довольно простым, но я не могу в этом разобраться…
Что я сделал до сих пор:
- Без
DISTINCT Match
условия
Market.objects.annotate(total_volume=Sum('issues__volume')).order_by("-total_volume")
Это работает, как и ожидалось, но Match
в моем наборе запросов один раз встречается несколько раз.
- Сначала попробуйте выполнить
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.
- Вторая попытка с
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
, но я не могу точно знать, почему!