Вычислить тип ForeignKey Процент (физическое лицо) Django ORM
Я хочу вычислить процент всех типов автомобилей, используя Django ORM, или сгруппировать все автомобили на основе их типов и вычислить процент. У меня есть несколько решений, но они старомодны и итеративны. Я собираюсь использовать этот запрос на приборной панели, где уже есть несколько запросов, вычисляющих различную аналитику. Я не хочу идти на компромисс в производительности, поэтому я предпочитаю один запрос. Вот структура моих таблиц (написанных) на Django:
class CarType:
name = models.CharField(max_length=50)
class Car:
car_type = models.ForeignKey(CarType, on_delete=models.CASCADE)
У меня есть функция полезности, которая имеет следующие детали:
- input => cars: (Queryset) of cars Django.
- output => список всех car_types (словарей), имеющих процент.
- [{'car_type': 'car01', 'percentage': 70, 'this_car_type_count': 20}, ...]
Что я пробовал до сих пор:
cars.annotate(
total=Count('pk')
).annotate(
car_type_name=F('car_type__name')
).values(
'car_type_name'
).annotate(
car_type_count=Count('car_type_name'),
percentage=Cast(F('car_type_count') * 100.0 / F('total'), FloatField()),
)
Но это решение дает 100% на всех типах автомобилей. Я знаю, что это странное поведение из-за values()
, который я использую, но я вроде как засунул его сюда.
F('total')
будет количество автомобилей в каждой группе (каждый тип автомобиля), а не общее количество автомобилей во всей таблице. Вот почему вы всегда получаете 100%. Вы можете достичь желаемого двумя запросами:
total = cars.count()
cars.annotate(
car_type_name=F('car_type__name')
).values(
'car_type_name'
).annotate(
car_type_count=Count('car_type_name'),
percentage=Cast(F('car_type_count') * 100.0 / total, FloatField())
)
Если вы действительно хотите сделать это в одном запросе вместо двух, вычисление total должно быть оконной функцией вместо обычного агрегата.