joh*_*ohn 0 python database sqlite pylons 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
Run Code Online (Sandbox Code Playgroud)
所有值都是cos_rad_lat和sin_rad_lat我预先计算的值,以优化计算.无论如何,当我运行以下查询时,
pq = Session.query(model.Location).filter(model.Location.great_circle_distance(loc) < 10)
Run Code Online (Sandbox Code Playgroud)
我收到以下错误,
line 809, in great_circle_distance
* math.cos(self.rad_lng - other.rad_lng)
TypeError: a float is required
Run Code Online (Sandbox Code Playgroud)
当我打印值时self.rad_lng,other.rad_lng我得到了,例如,
self.rad_lng: Location.rad_lng
other.rad_lng: -1.29154947064
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
你无法真正使用这种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
Run Code Online (Sandbox Code Playgroud)
你必须结合sqalchemy.func.*代替math.*的@great_circle_distance.expression方法,对所有的那种聪明的.不幸的是,你不能用sqlite做到这一点; 它不提供触发器功能
您可以使用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
Run Code Online (Sandbox Code Playgroud)