我正在使用Python和Sqlalchemy在Sqlite数据库中存储纬度和经度值。我为我的Location对象创建了hybrid method,
@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
我做错了什么?
答案 0 :(得分:5)
你无法真正使用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
method,以获得所有这种聪明才智。不幸的是,你不能用sqlite做到这一点;它doesn't provide trig functions
您可以使用PostgreSQL,或者您可以尝试add these functions to sqlite yourself:
编辑实际上并不难为sqlite添加功能:这是 NOT 测试。
必须将数学函数添加到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
答案 1 :(得分:0)
显然,你不能从那个字符串中得到一个浮点数。
这是因为你正在使用“self”,它作为调用的第一个参数,表示该方法是对象的一部分,而不是你传递的一些var。
你应该试试这个:
def great_circle_distance(self, first, 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(first.rad_lng - other.rad_lng)
+ self.sin_rad_lat
* other.sin_rad_lat
) * 3959
我在上面假设全局变量“self.cos_rad_lat”和“self.sin_rad_lat” 在程序中的其他位置使用正确的值启动,可能在同一对象的“init”部分。
答案 2 :(得分:0)
看起来你已经完成了所有事情,但不知何故,这种方法实际上并没有“杂交”。你有没有做过蠢事,比如实际将装饰器放在你的源代码中?