Как суммировать значение с дубликатами строк в запросе Django orm - PullRequest
1 голос
/ 19 апреля 2019

Цель

Я ищу способ получить сумму значений


Модель

class ModelX(models.Model):
    name = models.CharField(...)


class ModelA(models.Model):
    value = models.IntegerField()

class ModelB(models.Model):
    modela = models.ForeignKey(ModelA)
    modelxs = models.ManyToManyField(ModelX, through='ModelC')

class ModelC(models.Model):
    modelb = models.ForeignKey(ModelB)
    modelx = models.ForeignKey(ModelX)
    modelxx = models.ForeignKey(ModelX, related_name='modelcs')

Что я пробовал

Modelx.objects.values('name').annotate(
    total=Sum('modelcs__modelb__modela__value')
).values('total')

И

sum_qs = (
    ModelA
    .objects
    .filter(modelb_set__modelc_set__modelxx=OuterRef('id'))
    .values('modelb_set__modelc_set__modelxx_id')
    .order_by()
    .distinct()
    .values('value')
)

qs = ModelX.objects.annotate(
    total=Subquery(sum_qs.values('value')))

Проблема

  1. ModelC может содержать несколько строк с одинаковым отношением modelxx . Это приведет к дубликатам и к дублированию суммы 'value'
* * Пример 1 022

Ниже приведены примеры моделей, где я ожидаю увидеть 10, как указано в ожидаемых результатах вверху: edit

foo = ModelX.objects.create(name='Foo')
bar = ModelX.objects.create(name='Bar')
baz = ModelX.objects.create(name='Baz')

modela1 = ModelA.objects.create(value=10)
modela2 = ModelA.objects.create(value=10)

modelb1 = ModelB.objects.create(modela=modela1)
modelb2 = ModelB.objects.create(modela=modela2)

modelc1 = ModelC.objects.create(modelb=modelb1, modelx=foo, modelxx=bar)
modelc2 = ModelC.objects.create(modelb=modelb1, modelx=bar, modelxx=bar) # This would be a cause a duplicate as a relation to ModelX through modelxx
modelc3 = ModelC.objects.create(modelb=modelb1, modelx=baz, modelxx=baz)
modelc4 = ModelC.objects.create(modelb=modelb2, modelx=bar, modelxx=bar)

Ожидаемые результаты

РЕДАКТИРОВАТЬ {'Bar': 20, 'Baz': 10}

Это также может быть как QuerySet ModelX для сериализации


...