Вашето HAVING
се обработва правилно, но му предавате грешен израз. Изглежда, че използвате Python 2, тъй като релационното сравнение между низ и цяло число
'distance' < 25
не повдига изключение, но оценява на False
вместо. С други думи, вашата заявка е равна на
locations = db.session.query(...).having(False).all()
което обяснява защо получавате нулеви резултати:всички редове са изрично филтрирани от клаузата HAVING, както се вижда в отпечатаната версия:
...
HAVING false = 1 -- remove all rows
Решението е да използвате подходяща конструкция, като column()
, за да произведете израза:
locations = db.session.query(...).having(column('distance') < 25).all()
Не трябва да обвивате сложния израз на елемент от списъка за избор в select()
, което представлява израз SELECT. Или маркирайте text()
както е:
text('( 6371 * acos( cos( radians("53.6209798282177") ) * '
'cos( radians( lat ) ) * cos( radians( lng ) - radians("13.96948162900808") ) + '
'sin( radians("53.6209798282177") ) * sin( radians( lat ) ) ) ) '
'AS distance')
или изградете израза с помощта на модела:
(6371 *
func.acos(func.cos(func.radians(53.6209798282177)) *
func.cos(func.radians(Location.lat)) *
func.cos(func.radians(Location.lng) - func.radians(13.96948162900808)) +
func.sin(func.radians(53.6209798282177)) *
func.sin(func.radians(Location.lat)))).label('distance')
Бихте могли да подобрите четливостта на конструкцията на заявката си, като създадете функция за голямо разстояние в кръг , и с малко работа бихте могли да приложите хибриден метод
на Location
:
import math
def gc_distance(lat1, lng1, lat2, lng2, math=math):
ang = math.acos(math.cos(math.radians(lat1)) *
math.cos(math.radians(lat2)) *
math.cos(math.radians(lng2) -
math.radians(lng1)) +
math.sin(math.radians(lat1)) *
math.sin(math.radians(lat2)))
return 6371 * ang
class Location(db.Model):
...
@hybrid_method
def distance(self, lat, lng):
return gc_distance(lat, lng, self.lat, self.lng)
@distance.expression
def distance(cls, lat, lng):
return gc_distance(lat, lng, cls.lat, cls.lng, math=func)
locations = db.session.query(
Location,
Location.distance(53.6209798282177,
13.96948162900808).label('distance')).\
having(column('distance') < 25).\
order_by('distance').\
all()
Имайте предвид, че начинът, по който използвате HAVING за премахване на негрупови редове, не е преносим. Например в Postgresql наличието на клауза HAVING превръща заявка в групирана заявка, дори без клауза GROUP BY. Вместо това можете да използвате подзаявка:
stmt = db.session.query(
Location,
Location.distance(53.6209798282177,
13.96948162900808).label('distance')).\
subquery()
location_alias = db.aliased(Location, stmt)
locations = db.session.query(location_alias).\
filter(stmt.c.distance < 25).\
order_by(stmt.c.distance).\
all()