Din HAVING
håndteres korrekt, men du giver det det forkerte udtryk. Det ser ud til, at du bruger Python 2, da den relationelle sammenligning mellem en streng og et heltal
'distance' < 25
rejser ikke en undtagelse, men evaluerer til False
i stedet. Med andre ord er din forespørgsel lig med
locations = db.session.query(...).having(False).all()
hvilket forklarer, hvorfor du får nul resultater:alle rækker er eksplicit filtreret ud af HAVING-sætningen, som det ses i den trykte version:
...
HAVING false = 1 -- remove all rows
En løsning er at bruge en passende konstruktion, såsom column()
, for at fremstille udtrykket:
locations = db.session.query(...).having(column('distance') < 25).all()
Du bør ikke pakke det komplekse valglisteelement-udtryk ind i en select()
, som repræsenterer en SELECT-sætning. Mærk enten text()
som den er:
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')
eller byg udtrykket ved hjælp af modellen:
(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')
Du kan forbedre læsbarheden af din forespørgselskonstruktion ved at lave en funktion for store cirkelafstanden
a> , og med lidt arbejde kunne du implementere en hybridmetode
på 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()
Bemærk, at den måde, du bruger HAVING til at fjerne ikke-grupperækker, ikke er bærbar. For eksempel i Postgresql tilstedeværelsen af HAVING-sætning gør en forespørgsel til en grupperet forespørgsel, selv uden en GROUP BY-sætning. Du kan bruge en underforespørgsel i stedet:
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()