#mysql #django #python-3.x
#mysql #django #python-3.x
Вопрос:
У меня ситуация, когда у меня есть модель с именем trip
. У каждого отключения есть departure_airport
и an arrival_airport
, которые являются связанными полями и оба являются частью airport
модели. Каждый объект в модели airport имеет местоположение, представленное latitude
и longitude
полями.
Мне нужно иметь возможность принимать входные данные из двух (потенциально) отдельных местоположений аэропортов отправления и прибытия, используя что-то вроде формулы Haversine. Эта формула рассчитала бы расстояние от каждого аэропорта вылета / прибытия в базе данных до местоположения аэропортов, которые были приняты в качестве входных данных.
Трудная часть этого запроса заключается в том, что я аннотирую набор запросов на поездку местоположениями аэропортов отправления и прибытия, однако, поскольку существует два набора полей широты / долготы (по одному для каждого аэропорта) с одинаковым именем, и вы не можете использовать аннотированные поля в предложении sql where, я не могу использовать оба набора аэропортов в запросе.
Я полагаю, что решение состоит в использовании подзапроса к аннотированным полям, чтобы запрос выполнялся перед предложением where, однако я не смог определить, возможно ли это для этого запроса. Другой вариант — написать raw_sql.
Вот что у меня есть на данный момент:
GCD_FORMULA_TO = """3961 * acos(
cos(radians(%s)) * cos(radians(arrival_lat))
* cos(radians(arrival_lon) - radians(%s))
sin(radians(%s)) * sin(radians(arrival_lat)))"""
GCD_FORMULA_FROM = """3961 * acos(
cos(radians(%s)) * cos(radians(departure_lat))
* cos(radians(departure_lon) - radians(%s))
sin(radians(%s)) * sin(radians(departure_lat)))"""
location_to = Q(location_to__lt=self.arrival_airport_rad)
location_from = Q(location_from__lt=self.departure_airport_rad)
qs = self.queryset
.annotate(arrival_lat=F('arrival_airport__latitude_deg'))
.annotate(arrival_lon_to=F('arrival_airport__longitude_deg'))
.annotate(departure_lat=F('departure_airport__latitude_deg'))
.annotate(longitude_lon=F('departure_airport__longitude_deg'))
.annotate(location_to=RawSQL(GCD_FORMULA_TO, (self.arrival_airport.latitude_deg, self.arrival_airport.longitude_deg,
self.arrival_airport.latitude_deg)))
.annotate(location_from=RawSQL(self.GCD_FORMULA_FROM, (self.departure_airport.latitude_deg, self.departure_airport.longitude_deg,
self.departure_airport.latitude_deg)))
.filter(location_to and location_from)
return qs
Есть идеи? Также открыты для других способов сделать это.
Ответ №1:
Вы делаете это сложным способом.
Если в вашем коде python есть пара местоположений, используйте это:
from geopy.distance import distance
loc1 = (lat1, lng1)
loc2 = (lat2, lng2)
d = distance(loc1, loc2).km
Если вы запрашиваете базу данных, возможно, вы предпочли бы, чтобы она запускала PostGIS / Postgres, а не mysql,
таким образом, вы можете вычислить расстояние и принадлежность формы.
Синтаксис иногда неуклюж, но индексация работает отлично.
Вот пример вылета из лондонского аэропорта Хитроу:
SELECT a.airport_name,
ST_Distance('SRID=4326; POINT(-0.461389 51.4775)'::geography,
ST_Point(a.longitude, a.latitude)) AS distance
FROM arrival_airports a
ORDER BY distance;
В качестве отдельного вопроса вы могли бы рассмотреть возможность определения ПРЕДСТАВЛЕНИЯ прибытия и / или отправления в вашей таблице, а затем ОБЪЕДИНЕНИЯ с отдельной моделью для каждого представления.
Комментарии:
1. В идеальном мире я бы разобрался с sql-запросом, но сейчас у меня нет времени. Это отлично работает. Спасибо!