Я хотел бы сделать запрос, который получит запись с самым низким показателем, рассчитать на основе полей модели: view, unique_views и некоторый другой параметр, который является постоянным для запроса.
Мое предположение было использовать
session.query(func.min(get_metric(Post.views, Post.unique_views, 6))).first()
Но я получаю
Traceback (most recent call last):
File "/home/john/PycharmProjects/posts/testing.py", line 32, in <module>
session.query(func.min(get_metric(Post.views, Post.unique_views, 6))).first()
File "/home/john/PycharmProjects/posts/testing.py", line 19, in get_metric
metric = radians(views) + cos(unique_views) + asin(weight)
TypeError: must be real number, not InstrumentedAttribute
модель
class Post(db.Model):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
name = Column(String(20), unique=True, nullable=False)
views = Column(Integer, nullable=False)
unique_views = Column(Integer, nullable=False)
функция
def get_metric(views, unique_views, weight):
metric = radians(views) + cos(unique_views) + asin(weight)
return metric
Что мне не хватает?
Проблема в том, что математические функции Python работают с числами, а не с конструкциями SQLAlchemy. Чтобы создать выражение SQL, вам нужно использовать func
для создания выражений функции SQL. Вы можете использовать существующую функцию, изменив ее так, чтобы она принимала пространство имен, которое она использует для математики, в качестве аргумента:
import math
def get_metric(views, unique_views, weight, math=math):
metric = math.radians(views) + math.cos(unique_views) + math.asin(weight)
return metric
Теперь, когда вы хотите создать SQL, передайте func
как math:
session.query(func.min(get_metric(Post.views, Post.unique_views, 6, math=func))).first()
math
модуле. Некоторые функции не делают, однако:CBRT
не имеют аналогов,CEILING
имеет.ceil
,POWER
имеет.pow
... Я хотел инъекцию зависимостей , хотя, это чистый подход.