Django группировка по агрегации внешних ключей

У меня есть три таких модели:

class Coin(models.Model):
    symbol = models.Charfield()
    
class User(models.Model):
    phone_number = models.Charfield()
    
class Portfo(models.Model):

    class Meta:
        unique_together = (
            "user",
            "coin",
        )

    user = models.ForeignKey(
        to=User,
        on_delete=models.CASCADE,
        null=False,
        related_name="portfo",
    )
    coin = models.ForeignKey(
        to=Coin,
        on_delete=models.CASCADE,
        null=False,
        related_name="owners",
    )
    available = models.DecimalField(
        max_digits=40,
        decimal_places=20,
        default=Decimal(0),
    )
    blocked = models.DecimalField(
        max_digits=40,
        decimal_places=20,
        default=Decimal(0)
    )

Я собираюсь вычислить значение portfo каждого пользователя, поэтому я хочу объединить объекты portfo, сгруппированные по пользователям, следующим образом:

 [
    {
      "user_id":1,
      "portfo":{
           "coin_1_symbol":Decimal("1"),
           "coin_2_symbol":Decimal("2"),...
          }
    },
    {
     "user_id":2,...
    },...
]

или так:

[
 {
    "user_id":1,
    "portfo":[
           {"coin_symbol":"some_symbol","total":Decimal("1")},
           {"coin_symbol":"some_symbol2","total":Decimal("2")},...
    ]
  },...
]

Я пробовал агрегировать со значениями, но он возвращает такой результат:

>> Portfo.objects.exclude(available=0,blocked=0).annotate(total=Sum(F("available")+F("blocked"))).values("user_id","total","coin__symbol")

[{"user_id":1,"coin__symbol":"some_symbol","total":Decimal("1")},{"user_id":1,"coin__symbol":"some_symbol2", "total":Decimal("2")},...]

Есть ли способ сделать это с помощью django orm?

Вы не сможете сделать это просто используя annotate. Предпочтительный способ делать такие вещи - использовать вложенные сериализаторы.

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

for d in data: # data is your mentioned output from query.
    user_id = d["user_id"]
    if not converted_data:
        converted_data.append({"user_id":user_id,"portfo":[d]})
        continue
    for c in converted_data:
        if c["user_id"] == user_id:
            c["portfo"].append(d)
            break
    else:
        converted_data.append({"user_id":user_id,"portfo":[d]})
Вернуться на верх