extra()表达式中的Django外键
我试图使用Django extra()方法来过滤某个半径内的所有对象,就像下面的回答:但是我对“gcd”表达式有一些问题,因为我必须通过两个外键关系到达纬度和经度,而不是使用直接的模型字段 特别是,我有一个经验班:extra()表达式中的Django外键,django,django-models,django-filter,django-select-related,Django,Django Models,Django Filter,Django Select Related,我试图使用Django extra()方法来过滤某个半径内的所有对象,就像下面的回答:但是我对“gcd”表达式有一些问题,因为我必须通过两个外键关系到达纬度和经度,而不是使用直接的模型字段 特别是,我有一个经验班: class Experience(models.Model): starting_place_geolocation = models.ForeignKey(GooglePlaceMixin, on_delete=models.CASCADE,
class Experience(models.Model):
starting_place_geolocation = models.ForeignKey(GooglePlaceMixin, on_delete=models.CASCADE,
related_name='experience_starting')
visiting_place_geolocation = models.ForeignKey(GooglePlaceMixin, on_delete=models.CASCADE,
related_name='experience_visiting')
使用同一GooglePlaceMixin类的两个外键:
class GooglePlaceMixin(models.Model):
latitude = models.DecimalField(max_digits=20, decimal_places=15)
longitude = models.DecimalField(max_digits=20, decimal_places=15)
...
以下是我的代码,用于按起始位置筛选体验对象:
def search_by_proximity(self, experiences, latitude, longitude, proximity):
gcd = """
6371 * acos(
cos(radians(%s)) * cos(radians(starting_place_geolocation__latitude))
* cos(radians(starting_place_geolocation__longitude) - radians(%s)) +
sin(radians(%s)) * sin(radians(starting_place_geolocation__latitude))
)
"""
gcd_lt = "{} < %s".format(gcd)
return experiences \
.extra(select={'distance': gcd},
select_params=[latitude, longitude, latitude],
where=[gcd_lt],
params=[latitude, longitude, latitude, proximity],
order_by=['distance'])
我应该怎么做才能达到外键值?提前感谢您当您使用
extra
时(如文档中所述,应该避免),您实际上是在编写原始SQL。正如您可能知道的,要从ForeignKey获得价值,您必须执行JOIN。当使用Django ORM时,它会将这种奇特的双下划线转换为正确的JOIN子句。但是SQL不能。您也不能手动添加JOIN。正确的方法是坚持使用ORM,并为sin、cos、radians等定义一些自定义数据库函数。那很容易
class Sin(Func):
function = 'SIN'
然后像这样使用它:
qs = experiences.annotate(distance=Cos(Radians(F('starting_place_geolocation__latitude') )) * ( some other expressions))
请注意,奇特的双下划线再次出现,并按预期工作
你有这个想法
这是我的全部收藏,如果你喜欢从SO复制粘贴)
另外,您还可以面对设置输出\u字段
错误。然后必须将整个距离表达式包装到ExpressionWrapper
中,并为其提供一个output\u field=models.DecimalField()
参数
qs = experiences.annotate(distance=Cos(Radians(F('starting_place_geolocation__latitude') )) * ( some other expressions))