Python-SqlAlchemy:通过大圆距过滤查询?
问题内容:
我正在使用Python和Sqlalchemy将纬度和经度值存储在Sqlite数据库中。我已经为Location对象创建了一个混合方法,
@hybrid_method
def great_circle_distance(self, other):
"""
Tries to calculate the great circle distance between the two locations
If it succeeds, it will return the great-circle distance
multiplied by 3959, which calculates the distance in miles.
If it cannot, it will return None.
"""
return math.acos( self.cos_rad_lat
* other.cos_rad_lat
* math.cos(self.rad_lng - other.rad_lng)
+ self.sin_rad_lat
* other.sin_rad_lat
) * 3959
所有类似cos_rad_lat
和sin_rad_lat
的值都是我预先计算的值,以优化计算。无论如何,当我运行以下查询时,
pq = Session.query(model.Location).filter(model.Location.great_circle_distance(loc) < 10)
我收到以下错误,
line 809, in great_circle_distance
* math.cos(self.rad_lng - other.rad_lng)
TypeError: a float is required
当我打印的价值观self.rad_lng
和other.rad_lng
我得到的,例如,
self.rad_lng: Location.rad_lng
other.rad_lng: -1.29154947064
我究竟做错了什么?
问题答案:
您不能真的那样使用该math
模块:
>>> c = toyschema.Contact()
>>> c.lat = 10
>>> c.lat
10
>>> import math
>>> math.cos(c.lat)
-0.83907152907645244
>>> math.cos(toyschema.Contact.lat)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a float is required
你必须结合sqalchemy.func.*
代替math.*
的@great_circle_distance.expression
方法,对所有的那种聪明的。不幸的是,您也不能使用sqlite做到这一点;它不提供触发函数,
您可以使用PostgreSQL,也可以使用PostgreSQL,或者您可以尝试将以下函数添加到sqlite中:
编辑 它实际上不是要拼命的功能添加到sqlite的:这是 不是 测试。
必须将数学函数添加到sqlite:
engine = sqlalchemy.create_engine("sqlite:///:memory:/")
raw_con = engine.raw_connection()
raw_con.create_function("cos", 1, math.cos)
raw_con.create_function("acos", 1, math.acos)
class Location(...):
...
@hybrid_method
def great_circle_distance(self, other):
"""
Tries to calculate the great circle distance between
the two locations by using the Haversine formula.
If it succeeds, it will return the Haversine formula
multiplied by 3959, which calculates the distance in miles.
If it cannot, it will return None.
"""
return math.acos( self.cos_rad_lat
* other.cos_rad_lat
* math.cos(self.rad_lng - other.rad_lng)
+ self.sin_rad_lat
* other.sin_rad_lat
) * 3959
@great_circle_distance.expression
def great_circle_distance(cls, other):
return sqlalchemy.func.acos( cls.cos_rad_lat
* other.cos_rad_lat
* sqlalchemy.func.cos(cls.rad_lng - other.rad_lng)
+ cls.sin_rad_lat
* other.sin_rad_lat
) * 3959