В django-2.0 и выше, мы можем использовать .annotate(..)
с агрегатом, таким как Min
, и условием filter=...
для этого агрегата, например:
from django.db.models import <b>F, Min, Q</b>
t2=Min('time__time', filter=Q(<b>time__timing_point=to_point</b>))
t1=Min('time__time', filter=Q(<b>time__timing_point=from_point</b>))
Bib.objects.annotate(<b>dtime=t2-t1</b>)
Сначала введем две переменные:
t2
будет содержать наименьший time
для связанного Time
объекта с timing_point
to_point
(вероятно, есть только один); и
t1
будет содержать наименьший time
для связанного Time
объекта с timing_point
from_point
.
Затем делаем аннотацию dtime
с разницей между t2
и t1
.
Поскольку это все еще часть QuerySet
, мы можем даже заказать Bib
s на dtime
и т. Д.
Django преобразует это в запрос, который выглядит следующим образом:
SELECT bib.*,
(MIN(CASE WHEN time.timing_point_id = 2 THEN time.time ELSE NULL END) -
MIN(CASE WHEN time.timing_point_id = 1 THEN time.time ELSE NULL END)) AS dtime
FROM bib
LEFT OUTER JOIN time ON bib.id = time.bib_id GROUP BY bib.id
С 2
и 1
в действительности первичными ключами to_point
и from_point
соответственно.
Это может повысить эффективность запроса, если вы отфильтруете и модель Timing
:
from django.db.models import F, Min, Q
t2=Min('time__time', filter=Q(time__timing_point=to_point))
t1=Min('time__time', filter=Q(time__timing_point=from_point))
Bib.objects.filter(
<b>time__timing_point__in=[from_point, to_point]</b>
).annotate(dtime=t2-t1)
это приведет к запросу, который будет выглядеть так:
SELECT bib.*,
(MIN(CASE WHEN time.timing_point_id = 2 THEN time.time ELSE NULL END) -
MIN(CASE WHEN time.timing_point_id = 2 THEN time.time ELSE NULL END)) AS dtime
FROM bib LEFT OUTER JOIN time ON bib.id = time.bib_id
<b>WHERE time.timing_point_id IN (1, 2)</b>
GROUP BY bib.id