Формат целого числа count в проценты внутри аннотации в Djnago rest
Мне нужно отправить процент подсчетов в вызове API в DRF. Я подсчитал количество и прикрепил к набору запросов с помощью annotate. Но на самом деле мне нужен процент, а не количество.
TYPES = ((1,'cold'),
(2,'humid'),
(3,'hot'))
from django.db.models import Q,Count
class Destinations(models.Model):
continent = models.CharField()
/............/
class Packages(models.Model):
location = models.Foreignkey(Destination,on_delete=models.CASCADE,related_name='packages')
place_type = models.CharField(
max_length=1,
choices=TYPES,
default=""
Мое мнение:
Я использую функцию list внутри modelviewset, примерно так:
Destiantion = Destination.objects.all().annotate(total_packages=Count('packages'),
cold_count=Count('packages',filter=Q(packages__place_type=1)),
humid_count=Count('packages',filter=Q(packages__place_type=2)),
hot_count =Count('packages',filter=Q(packages__place_type=3)))
Здесь я получаю ответ в виде количества типов пакетов в атрибутах, но я хочу получить процентное соотношение типов пакетов, например 25%, делая cold_count*100/total_packages
, но не могу использовать это внутри annotate.
Есть метод count(), который может быть полезен, но если я использую его, мне придется сделать 4 отдельных запроса и, возможно, написать еще один API только для этого. Поэтому я должен использовать annotate. Но как?
Вам стоит попробовать
from django.db.models.functions import Coalesce
Destination.objects.all().annotate(
total_packages=Count('packages'),
cold_count_percent=Coalesce(100.0 * Count('packages',filter=Q(packages__place_type=1)) / Count('packages'), 0),
humid_count_percent=Coalesce(100.0 * Count('packages',filter=Q(packages__place_type=2)) / Count('packages'), 0),
hot_count_percent=Coalesce(100.0 * Count('packages',filter=Q(packages__place_type=3)) / Count('packages'), 0),
)
Также если вам нужно обработать случай, когда Count('packages')=0
, вам нужно что-то вроде этого:
from django.db.models.functions import Coalesce
Destination.objects.all().annotate(
total_packages=Count('packages'),
cold_count_percent=Coalesce(div_zero(100.0 * Count('packages',filter=Q(packages__place_type=1)) / Count('packages'), 'total_packages'), 0),
humid_count_percent=Coalesce(div_zero(100.0 * Count('packages',filter=Q(packages__place_type=2)) / Count('packages'), 'total_packages'), 0),
hot_count_percent=Coalesce(div_zero(100.0 * Count('packages',filter=Q(packages__place_type=3)) / Count('packages'), 'total_packages'), 0),
)
где div_zero
ниже:
from django.db.models import Case, Value, FloatField
from django.db.models.expressions import When
INFINITY = 1000000000000
def div_zero(result, divisor):
return Case(
When(**{
divisor: 0,
'then': Value(INFINITY, FloatField()),
}),
default=result,
output_field=FloatField(),
)