Модель Django - невозможно сделать агрегированную сумму с разделителем из тысячи запятых и десятичных точек

У меня следующая модель:

class Example(models.Model):
    project_id = models.IntegerField(
        null=False, 
        blank=False, 
        default=0,
    )
    field1 = models.CharField(
        max_length=250,
        null=True, 
        blank=True,
    )
    field2 = models.CharField(
        max_length=250,
        null=True, 
        blank=True,
    )
    total = models.CharField(
        max_length=250,
        null=True, 
        blank=True,
    )

Пример данных:

project_id field1 field2 total
1 1,323 4,234.55 5,557.55
2 1,000 2 1,002
3 1.23 3 4.23

total = field1 + field2

Я хотел бы суммировать все total значения.

Вот что я пробовал views.py:

context['total'] = Example.objects.filter(project_id=pid).aggregate(Sum('total'))

Текущий выход:

{'total': 10.23}

Ожидаемый выход:

{'total': 6,563.78}

Или, если это невозможно, по крайней мере: 6563.78, чтобы я мог отформатировать числа позже.

Поскольку проект требует разделителя запятых и десятичных точек, я не могу изменить или изменить поля модели и использовать FloatField.

Любая помощь будет очень признательна

Поскольку вы говорите, что не можете изменить тип данных в самих полях, вы можете добиться этого, используя функции базы данных Replace и Cast (конечно, это не идеально - лучше исправить типы данных в самой модели).

Это должно работать - по крайней мере, на базе данных производственного класса, таких как PostgreSQL (я не уверен, что это будет работать на SQLite - если вы используете его в производстве, то у вас действительно есть проблемы):

from django.db.models import FloatField, Value
from django.db.models.functions import Cast, Replace

context['total'] = Example.objects.annotate(
    cleaned_total=Replace('total', Value(','), Value(''))
).annotate(
    float_total=Cast('cleaned_total', FloatField())
).aggregate(Sum('float_total'))

Что это делает:

  1. Выполнение замены поля для удаления запятых.
  2. Передача очищенного значения в функцию cast, которая преобразует очищенные строки в плавающие значения.
  3. Выполнение суммы над результатом.

Вот альтернативные варианты, которые вы могли бы рассмотреть в случае, если ответ solarissmoke не то, что вы ищете:

  1. Поскольку агрегация/аннотация требует реальных полей базы данных, можно отказаться от агрегации/функций базы данных и просмотреть набор запросов в python, преобразовать значения в нужные числовые типы (возможно, с помощью метода модели?) и суммировать их. При этом производительность заметно ухудшится.

    .
  2. Вы можете создать дополнительные числовые поля модели, которые автоматически заполняются после save (возможно, переопределив поведение сохранения по умолчанию или используя сигналы ). А затем используйте агрегацию и на этих числовых полях. Вы должны быть осторожны в отношении возможных конфликтов с оригинальными Sum, которые могут привести к неправильным результатам (например, пропущенные обновления, другое пользовательское поведение).CharField

Вернуться на верх