Reputation: 103
I am using SQLAlchemy to handle the database of a Flask webapp that I am currently working on. As a function of the website, I want users to be able to search for other users with location and radius from that specified location as parameters. So naturally, not knowing much about SQLAlchemy, I tried with this expression:
profiles = User.query.filter(sqrt(abs(User.latitude - location.latitude)**2 + abs(User.longitude - location.longitude)**2) <= radius)
Explanation: I want to return all the users located at a distance within the specified radius from the specified location.
However, it then gives me this error:
Traceback (most recent call last):
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\Frederik\Desktop\start\app\routes.py", line 136, in explore
profiles = User.query.filter_by(sqrt(abs(User.latitude - location.latitude)**2 + abs(User.longitude - location.longitude)**2) <= radius)
TypeError: bad operand type for abs(): 'BinaryExpression'
How will I be able to pass a model parameter inside an equation as a condition in a query search like this one?
After the suggestion from frost-nzcr4, I tried to go with the @hybrid_method
decorator, since that seems to be the one that fits the best in my case.
(I came to that conclusion by reading the docs: https://docs.sqlalchemy.org/en/13/orm/extensions/hybrid.html)
Therefore, I added this to my model:
@hybrid_method
def is_nearby(self, latitude, longitude, radius):
return sqrt((self.latitude - latitude)**2 + (self.longitude - longitude)**2) <= radius
(I also removed the abs()
functions inside of the expression, because the squaring already returns an exclusively positive value..)
And this to my route instead of the old expression:
profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius))
(FYI I then saved my code, updated my database and restarted the flask server)
I tried the query search again, and... I got this error:
Traceback (most recent call last):
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\Frederik\Desktop\start\app\routes.py", line 134, in explore
profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius))
File "C:\Users\Frederik\Desktop\start\app\models.py", line 64, in is_nearby
return sqrt((self.latitude - latitude)**2 + (self.longitude - longitude)**2) <= radius
TypeError: unsupported operand type(s) for ** or pow(): 'BinaryExpression' and 'int'
The location variable isn't containing a sqlalchemy model. It's an object from the Geopy Python library. However, its dependencies .latitude
and .longitude
are both just floats. As an example it could be defined like this:
location = geolocator.geocode("NYC, New York, USA")
And this is my User model with its two dependencies relevant to this problem:
class User(UserMixin, db.Model):
...
latitude = db.Column(db.Float, index=True)
longitude = db.Column(db.Float, index=True)
...
Why is it that these properties of the model can't be applied specific operands ie. squaring within a condition in a query search? And how can I get around it in my case?
PS
Thank you so much for commenting frost-nzcr4. It means a lot!
Ok, so now after another suggestion from frost-nzcr4, I changed the is_nearby
method to this:
(Here func
is referencing to from sqlalchemy import func
)
@hybrid_method
def is_nearby(self, latitude, longitude, radius):
return func.sqrt(func.pow(self.latitude - latitude, 2) + func.pow(self.longitude - longitude, 2)) <= radius
Also, the query search statement is now written like this:
profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius)).all()
And it works! It gets rid of the previous error.. But then comes another..:
Traceback (most recent call last):
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\default.py", line 552, in do_execute
cursor.execute(statement, parameters)
sqlite3.OperationalError: no such function: sqrt
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\Frederik\Desktop\start\app\routes.py", line 135, in explore
profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius)).all()
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\orm\query.py", line 3161, in all
return list(self)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\orm\query.py", line 3317, in __iter__
return self._execute_and_instances(context)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\orm\query.py", line 3342, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 988, in execute
return meth(self, multiparams, params)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\sql\elements.py", line 287, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 1107, in _execute_clauseelement
distilled_params,
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 1248, in _execute_context
e, statement, parameters, cursor, context
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 1466, in _handle_dbapi_exception
util.raise_from_cause(sqlalchemy_exception, exc_info)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\util\compat.py", line 383, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\util\compat.py", line 128, in reraise
raise value.with_traceback(tb)
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "c:\users\frederik\appdata\local\programs\python\python37\lib\site-packages\sqlalchemy\engine\default.py", line 552, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such function: sqrt
[SQL: SELECT user.id AS user_id, user.name AS user_name, user.location AS user_location, user.latitude AS user_latitude, user.longitude AS user_longitude, user.username AS user_username, user.email AS user_email, user.password_hash AS user_password_hash
FROM user
WHERE sqrt(pow(user.latitude - ?, ?) + pow(user.longitude - ?, ?)) <= ?]
[parameters: (55.8125143, 2, 12.4687513, 2, '10')]
(Background on this error at: http://sqlalche.me/e/e3q8)
It seems like there's no equivalent to the Math module's square root function inside of sqlalchemy.func
.
If there is, what is it called then? And if there isn't, what can I then do?
Upvotes: 0
Views: 1263
Reputation: 1620
The answer is a bit complex:
@hybrid_method
/@hybrid_property
.sqlalchemy.func
for pow
, sqrt
and so on.In your case sqlite3.OperationalError: no such function: sqrt
see https://stackoverflow.com/a/12731982/5274713. In worst case you've to use plain SQL expression as in https://stackoverflow.com/a/2002448/5274713
Upvotes: 1