Агрегация суммы по полю JsonField с помощью Django Orm
У меня есть модель в моем проекте django со следующей структурой:
class Portfolio(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    entered_usdt = models.DecimalField(max_digits=22, decimal_places=2, default=0)
    detail = models.JSONField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
 Я хотел бы иметь Sum агрегатную функцию над ненулевыми значениями ключей detail поля записей данной модели в базе данных.
Это поле может быть пустым или иметь разные ключи для каждой записи в базе данных, например, я захватил участок базы данных, чтобы лучше объяснить, что я имею в виду:

 Для этой цели я написал следующий фрагмент кода на чистом Python, который сначала извлекает ключи для записей, чьи detail не пусты, а затем вычисляет сумму всех этих ключей во всех этих записях.
import json
from bestbuy.models import Portfolio
from django.db.models import Q
def calculate_sum_of_all_basket_coins():
    non_zero_portfolios_details = list(Portfolio.objects.filter(~Q(detail={})).values('detail'))
    detail_list = list()
    result = {}
    for detail in non_zero_portfolios_details:
        detail_list.append(json.loads(portfolio))
    for d in detail_list:
        for k in d.keys():
            if k in result: 
                result[k] += d.get(k, 0.0)
            else:
                result[k] = d.get(k, 0.0)
    return result
 Я знаю, что этот метод совсем не хорош, потому что по мере увеличения количества записей в базе данных, этой функции требуется все больше и больше времени для выполнения этого вычисления.
Я также прочитал следующие посты в блоге и вопросы, чтобы узнать что-то больше о django orm и возможности его поддержки этого вычисления и, например, я обнаружил
с чем-то вроде функции KeyTextTransform, но все трюки в приведенных ниже ссылках предназначены для определенного ключа или ключей json-поля в базе данных, а не для каких-то неизвестных ключей и т.д.
Как я могу получить набор агрегированных значений этого поля, используя django orm?
Лучшей практикой здесь будет создание менеджера моделей, таким образом, его можно вызвать следующим образом:
Projects.objects.with_sums()
Их можно даже соединить в цепочку следующим образом:
Projects.objects.filter(…).with_sums()
Вам просто нужно аннотировать объект запроса, возвращаемый методом модели, суммой каждого поля - однако вам придется запрашивать сумму каждого поля отдельно.
Если вы хотите немного оптимизировать работу, вы можете позволить with_sums() принимать аргумент, в котором вы можете указать, для каких полей вы хотите получить суммы - я рекомендую передавать полный путь к json-полю (т.е.: "foo__bar__field").
References
https://docs.djangoproject.com/en/4.0/topics/db/managers/
https://docs.djangoproject.com/en/4.0/topics/db/aggregation/
https://docs.djangoproject.com/en/4.0/ref/models/querysets/#annotate