Django: фильтр по аннотированному значению - PullRequest
1 голос
/ 27 марта 2019

У меня есть ситуация, когда у меня есть модель под названием trip. Каждая поездка имеет departure_airport и arrival_airport, которые являются связанными полями и обе являются частью модели airport. Каждый объект в модели аэропорта имеет местоположение, представленное полями latitude и longitude.

Мне нужно иметь возможность получать информацию из двух (потенциально) отдельных мест вылета и прилета, используя что-то вроде формулы Хаверсайна. Эта формула рассчитывает расстояние от каждого аэропорта вылета / прилета в базе данных до местоположения аэропортов, которые были взяты в качестве входных данных.

Сложная часть этого запроса состоит в том, что я аннотирую набор запросов на поездки с указанием местоположения аэропортов отправления и прибытия, поскольку есть два набора полей широты / долготы (по одному для каждого аэропорта) с одинаковым именем, и вы можете ' Я не могу использовать аннотированные поля в предложении 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 Ответ

1 голос
/ 27 марта 2019

Вы делаете это трудным путем.

Если в вашем коде Python есть пара местоположений, используйте this :

from geopy.distance import distance

loc1 = (lat1, lng1)
loc2 = (lat2, lng2)
d = distance(loc1, loc2).km

Если вызапрашивая базу данных, возможно, вы бы предпочли, чтобы она работала с PostGIS / Postgres, а не с mysql, поэтому вы можете вычислить distance и сформировать членство.Синтаксис иногда находится на неуклюжей стороне , но индексация работает отлично.Вот пример ухода из лондонского Хитроу:

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;

В качестве отдельного вопроса вы можете рассмотреть определение ВИДА прибытия и / или отъезда на своем столе, а затем ПРИСОЕДИНИТЬСЯ, с отдельной моделью для каждого вида..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...