Аннотировать на основе расчета в ManyToManyField - PullRequest
0 голосов
/ 22 марта 2020

Я пытаюсь аннотировать модель Django, вычисляя нетривиальное выражение, используя свойство ManyToManyField в модели.

Ситуацию можно перевести в следующую простую примерную структуру: «платежи», которые следует разделить между несколькими «компаниями» в соответствии с их относительными размерами. Какие компании участвуют в данном платеже, сохраняется как ManyToManyField:

class Company:
  relative_size = models.DecimalField()   ## can be assumed to add up to 1 among all companies

class Payment(models.Model):
  companies = models.ManyToManyField(Company, related_name='payments', blank=True)
  amount = models.DecimalField()

. Сейчас я пытаюсь запросить общую сумму, в которой участвовала каждая компания. Если доля была одинаковой в каждом из платежи, это будет так же просто, как

companies = Company.objects.annotate(total_payments=Sum(F('payments__amount')*F('relative_size')))
for company in companies:
  print("Company %s: %s" (str(company), total_payments))

Но как это сделать в случае, когда мне нужно рассчитать правильную долю для каждого платежа, на основе которого участвовали компании? Я подозреваю, что должен использовать Subquery, но не смог адаптировать примеры из документации к моему случаю.

PS: В качестве обходного пути я реализовал это в "Python", а не в запросах как следует:

payments_annotated = Payment.objects.annotate(sum_involved_companies_sizes=Sum(F('companies__relative_size')))
companies = Company.objects.all()
for c in companies:
  c.sum = Decimal('0.0')
  for p in payments_annotated.filter(companies__id=c.id):
    c.sum += p.amount * c.relative_size/p.sum_involved_companies_sizes

Но я думаю, что это должно быть возможно и более эффективно в системе запросов, поэтому я надеюсь, что эксперт может помочь? Спасибо!

...