【问题标题】:How to do arthmetic on Django 'F' types?如何对 Django 'F' 类型进行算术运算?
【发布时间】:2020-10-11 19:32:28
【问题描述】:

我有一个 Event 模型,为了简单起见,它只有一个 lat 和 lon FloatField()。

从python原生的“geopy.distance”库中,你可以像这样获取两个坐标之间的距离:

from geopy.distance import distance
home = (33.28473, -117.20384)
event = (33.829384, -117.38932)
distance = distance(home, event).miles  #returns a float 

在我的应用程序上下文中,我需要按位置对所有事件进行排序。我尝试了标准的 django 注释语法:

Event.objects.all().annotate(distance=distance( (F('lat'),F('lon')), home ).miles).order_by('distance')

但我从 geopy 库中收到以下错误:

TypeError: float() argument must be a string or a number, not 'F'

奇怪的是,这行得通:

>>> def foo(x):
        return x * 2
>>> Event.objects.all().annotate(cutomField=foo(F('field')))

似乎你可以用 F 类型做算术,但 geopy 似乎不知道这一点。

是否有将 F 类型转换为浮点数以便 geopy 可以处理该字段?

【问题讨论】:

  • 您使用的是哪个数据库? Django 对 PostgreSQL + PostGIS + GeoDjango 提供了不错的支持
  • @IainShelvington MySQL
  • 如果可以的话,我强烈建议您迁移到 PostgreSQL。 QuerySet 注释和排序发生在数据库级别,您需要一个支持地理空间功能/查询的数据库
  • @IainShelvington 我同意,但这不是地理空间功能。将自定义函数引入 SQL 并注释/创建浮点字段的原理。这可能吗?
  • 一个地理空间函数,它返回地球上两点之间的距离。您需要定义一个调用st_distance_sphere的自定义数据库函数

标签: django django-models django-rest-framework


【解决方案1】:

Django 支持查询表达式的求反、加法、减法、乘法、除法、模算术和幂运算符,使用 Python 常量、变量甚至其他表达式。

F() 对象表示模型字段或注释列的值。它可以引用模型字段值并使用它们执行数据库操作,而无需将它们从数据库中拉出到 Python 内存中。

相反,Django 使用 F() 对象生成描述数据库级别所需操作的 SQL 表达式。

以上详情来自django官方documentation link

例如 1。

def foo(x):
    return x*2

qs = MyModel.objects.filter().annotate(res=foo(F('colN')))
print(qs.query)

输出:

SELECT col1, col2, ("model_table"."colN" * 2) AS "res" FROM "model_table"

eg 2(考虑另一个函数)。

def foo_power(x):
    return x**2 ## POWER of 2

qs = MyModel.objects.filter().annotate(res=foo_power(F('colN')))
print(qs.query)

输出: SELECT col1, col2, (POWER("music_movie"."title",2)) AS "res" FROM "model_table"

这表明计算发生在数据库端:

对于 geopy.distance 情况:

对于自定义集合计算,我们需要在 django 内置数据库函数的帮助下编写自己的 Func。 可以关注https://docs.djangoproject.com/en/3.0/ref/models/expressions/#func-expressions

有没有办法将 F 类型转为浮点数,以便 geopy 可以处理该字段?

不,你不能输入 cast F() 即 'django.db.models.expressions.F'> 来浮动。

因为:

def foo_power(x):
    print(type(x), x)
    return x**2 ## POWER of 2

qs = MyModel.objects.filter().annotate(res=foo_power(F('colN')))

输出: F(title)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-03
    • 2023-01-11
    • 2013-02-06
    • 1970-01-01
    • 2021-09-05
    • 2023-03-29
    • 2014-10-02
    • 1970-01-01
    相关资源
    最近更新 更多