Как передать параметр модели в условие фильтра в SQLAlchemy - PullRequest
0 голосов
/ 23 марта 2020

Я использую SQLAlchemy для обработки базы данных Flask веб-приложения, над которым я сейчас работаю. Как функция веб-сайта, я хочу, чтобы пользователи могли искать других пользователей с местоположением и радиусом от указанного местоположения в качестве параметров. Поэтому, естественно, не слишком разбираясь в SQLAlchemy, я попытался использовать это выражение:

profiles = User.query.filter(sqrt(abs(User.latitude - location.latitude)**2 + abs(User.longitude - location.longitude)**2) <= radius)

Объяснение: Я хочу вернуть всех пользователей, находящихся на расстоянии в пределах указанного радиуса от указанного местоположения.

Тем не менее, это дает мне такую ​​ошибку:

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'

Как я могу передать параметр модели внутри уравнения в качестве условия в поисковом запросе, например этот?

Редактировать

После предложения от frost-nzcr4 я попытался go с помощью декоратора @hybrid_method, так как это кажется быть тем, который подходит лучше всего в моем случае.

(я пришел к такому заключению, прочитав документы: https://docs.sqlalchemy.org/en/13/orm/extensions/hybrid.html)

Поэтому я добавил это к моя модель:

@hybrid_method
def is_nearby(self, latitude, longitude, radius):
    return sqrt((self.latitude - latitude)**2 + (self.longitude - longitude)**2) <= radius

(я также удалил функции abs() внутри выражения, потому что квадрат уже возвращает исключительно положительное значение ..)

И это вместо моего маршрута старого выражения:

profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius))

(К вашему сведению, я спас de, обновил базу данных и перезапустил сервер flask)

Я снова попытался выполнить поиск по запросу, и ... Я получил эту ошибку:

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'

Переменная местоположения не содержащий модель sqlalchemy. Это объект из библиотеки Geopy Python . Однако его зависимости .latitude и .longitude являются просто плавающими. В качестве примера это можно определить так:

location = geolocator.geocode("NYC, New York, USA")

И это моя модель пользователя с двумя зависимостями, относящимися к этой проблеме:

class User(UserMixin, db.Model):
    ...
    latitude = db.Column(db.Float, index=True)
    longitude = db.Column(db.Float, index=True)
    ...

Почему это так? эти свойства модели не могут быть применены, например c операнды ie. квадрат в условии при поиске запроса? И как мне обойти это в моем случае?

PS

Большое спасибо за комментарий frost-nzcr4 . Это много значит!

Редактировать 2

Хорошо, так что теперь, после другого предложения от frost-nzcr4 , я изменил метод is_nearby на этот: (Здесь func ссылается на 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

Кроме того, оператор поиска запроса теперь записывается так:

profiles = User.query.filter(User.is_nearby(latitude=location.latitude, longitude=location.longitude, radius=radius)).all()

И это работает! Это избавляет от предыдущей ошибки .. Но потом приходит другое ..:

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)

Кажется, что нет эквивалента квадратной функции root модуля Math внутри sqlalchemy.func.

Если есть, как это тогда называется? А если нет, что я тогда могу сделать?

1 Ответ

1 голос
/ 24 марта 2020

Ответ немного сложен:

  1. Опишите логи c через @hybrid_method / @hybrid_property.
  2. Используйте sqlalchemy.func для pow, sqrt и т. Д.
  3. Убедитесь, что в вашей базе данных реализованы эти функции.

В вашем случае sqlite3.OperationalError: no such function: sqrt см. { ссылка }. В худшем случае вы должны использовать простое SQL выражение, как в { ссылка }

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