Модель 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'))
Что это делает:
- Выполнение замены поля для удаления запятых.
- Передача очищенного значения в функцию cast, которая преобразует очищенные строки в плавающие значения.
- Выполнение суммы над результатом.
Вот альтернативные варианты, которые вы могли бы рассмотреть в случае, если ответ solarissmoke не то, что вы ищете:
Поскольку агрегация/аннотация требует реальных полей базы данных, можно отказаться от агрегации/функций базы данных и просмотреть набор запросов в python, преобразовать значения в нужные числовые типы (возможно, с помощью метода модели?) и суммировать их. При этом производительность заметно ухудшится.
.Вы можете создать дополнительные числовые поля модели, которые автоматически заполняются после
save
(возможно, переопределив поведение сохранения по умолчанию или используя сигналы ). А затем используйте агрегацию и на этих числовых полях. Вы должны быть осторожны в отношении возможных конфликтов с оригинальнымиSum
, которые могут привести к неправильным результатам (например, пропущенные обновления, другое пользовательское поведение).CharField