Вычислить тип 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 должно быть оконной функцией вместо обычного агрегата.

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