Аннотация запросов Django не поддерживает вычисление math.tan()
У меня есть сайт django 3.2/mysql. Одна из таблиц, Flights
, имеет два столбца, angle
и baseline
. Эти два столбца объединены в представлении для отображения значения altitude
с помощью формулы altitude = baseline * tan(angle)
. Я создаю форму поиска для этой таблицы, и пользователь хочет искать рейсы, используя minimum altitude
и maximum altitude
.
Мой обычный подход к проблеме состоит в том, чтобы собрать входные данные из формы поиска, создать соответствующие Q-операторы и использовать запрос к таблице с фильтрами, основанными на Q-операторах. Однако, поскольку нет поля altitude
, я должен аннотировать запрос полем altitude value
, чтобы оператор Q с высотой работал.
Похоже, что в аннотации запроса нельзя использовать выражение типа math.tan(field_name)
. Например,
Flights.objects.annotate(altitude_m=ExpressionWrapper(expression=(F('baseline') * math.tan(F("angle"))), output_field = models.FloatField(),),)
генерирует ошибку builtins.TypeError: must be real number, not F
где выражение
Flights.objects.annotate(altitude_m=ExpressionWrapper(expression=(F('baseline') * F("angle")), output_field = models.FloatField(),),)
не генерирует ошибку, но и не дает правильного значения.
Есть ли способ аннотировать запрос к таблице Flights
со значением altitude
, чтобы я мог добавить фильтр типа Q(altitude__gte= min_altitude)
к запросу? Или лучше всего (1) вернуться к существующим ~1000 строкам в таблице Flights
и добавить столбец altitude
и вставить вычисленное значение, или (2) отфильтровать запрос Flights
по другим критериям поиска и в python вычислить высоту для каждого объекта Flights в отфильтрованном наборе запросов и отбросить те, которые не соответствуют критериям поиска высоты?
Примечание: Я несколько упростил описание проблемы, описав только одно значение высоты. На самом деле существует 2 значения высоты, одно в метрах, другое в футах.
Спасибо!
Используйте функцию базы данных Tan
from django.db.models.functions import Tan
Flights.objects.annotate(
altitude=ExpressionWrapper(expression=F('baseline') * Tan('angle'), output_field=models.FloatField())
)