为什么在尝试更新 geoDjango Point objects 时没有保存任何内容?

Why is nothing being saved when trying to update geoDjango Point objects?


已解决:查看我自己的回答以获得解释。


我正在写一个 API 来帮助我在需要时维护我的数据库。

我的 API 的一个功能是更新所有相关 object 的特定 geoDjango Point 字段,这要归功于我的模型的专用方法(这是非常无用的重新编辑 EDIT 1,见下文)。

我一直面临的问题如下:在多个 object 上调用该方法时似乎没有任何内容保存到数据库中,即使对 save 方法的调用似乎在浏览 object 时工作。

参见 EDIT 2,我发现这个问题是 geoDjango Point objects 特有的(其他所有内容都按预期更新)。

下面是我的模型:

models.py

class Location(geoModels.Model):
    coord_field = geoModels.PointField(blank=True, null=True)
    valTest = models.CharField(max_length=100, default="tagada") # only used to understand why coord_field can't be updated properly
    def update_coord_field(self):
        # some stuff is being done
        self.coord_field = Point(
            newLong,
            newLat,
            srid=3857 # I am trying to update that value
        )
        # nothing more
由于 Google 地图 API,正在生成

newLongnewLat。 由于 Google 地图似乎与 SRID 3857 一起工作,而 GeoDjango 在创建新的 Point 时默认使用 SRID 4326,我想强制 self.coord_field 的 SRID 为 SRID 3857(我一直面临不一致的距离演算,所以我正在尝试使用 SRID 来解决这个问题)。

现在这是我的脚本:

script.py

from MyApp import models as MyAppModels
def update_all_coord_field():
    for location in MyAppModels.Location.objects.all():
        print("  old SRID : ", location.coord_field.srid)
        location.update_coord_field()
        location.save()
        print("  new SRID : ", location.coord_field.srid)
update_all_coord_field()

但是当再次尝试执行我的脚本时(或者只是尝试使用我的新值属性),我只能观察到没有任何东西被保存到数据库中(它仍然 print [的旧值=28=] 所有 Locationobjects).

我的脚本是如何执行的:

python manage.py shell
exec(script.py)

如果我调用我的脚本两次,这里是以下追溯(只有一个 object 让想法可以理解):

exec(script.py)
  old SRID : 4326
  new SRID : 3857 # so apparently object has been updated...
exec(script.py)
  old SRID: 4326 # ...but this line proves that the updated value has not been pushed to the database
  new SRID: 3857 

你知道为什么这不起作用吗?


第一次编辑:@JohnMoutafis 向我指出,已经有一个函数可以更改 Point object 的 SRIDtransform

Location.objects.get(pk=pk).transform(3857) # define a new value of SRID

有用,但没有解决我的问题!请注意,我没有使用 transform 方法更新我的代码。


第二次编辑:我经历了很多痛苦才明白不是 save 方法不起作用!实际上,如果我尝试更新 MyAppModel 的 "casual" 数据字段,一切正常并按预期更新。真正的问题只是我的 coord_field 属性 无法 更新,我不知道为什么。

在我的脚本中,我一方面尝试了上面解释的内容,另一方面我也尝试了以下手动更新(而不是通过我的模型的自定义方法)coord_field:

MyAppModels.Location.objects.filter(pk=pk).update(
    geoCoord=Point(location.geoCoord.x, location.geoCoord.y, srid=3857),
    valTest="meat"
)

因此,如果我再次执行我的脚本,我会看到 valTest 已正确更新(很好!),但 geoCoord 仍然是旧值! :-( 错误的 SRID 和所有内容。所以,我认为我在更新 geoDjango Point object 时确实遇到了问题,因此我会更新我的问题的标题!

基于此gis.stackexchange post,我假设您最初声明的每个点都没有显式 srid,因此 GeoDajngo 假设您必须在 4326 上声明它。

  1. 您需要在数据库中明确声明每个点。
    这是一个脚本,可以帮助您利用现有的积分来做到这一点。

    for item in Location.objects.all():
        item.coord_field = Point(item.coord_field.x, item.coord_field.y, srid=4326)
        item.save()
    
  2. 您可以使用 transform 而不是您的自定义方法来更改您的点数 srid

    Location.objects.all().transform(3857)
    

因评论而编辑:

由于@KrazyMax 在评论中提供了说明,他需要计算球面距离。我在这里做了一个 post:

已解决:我的结论是,一旦您指定了 Point 中的 SRID,您以后就无法更改它。即使 transform 方法也不会改变 SRID,而只会进行一些转换 就地 ,而不会改变 [=14] 的原始 SRID =].实际上,我认为当我写:

coord_field = geoModels.PointField(blank=True, null=True)

默认的 4826 SRID 已经一次性设置到数据库的相应列(并且只有这个 SRID 可以用于该列)。所以,即使我写:

self.coord_field = Point(newLong, newLat, srid=newSRID)

我无法将另一个 SRID 关联到我的观点。将要计算一些微积分,但最终 Point 属性仍将受到初始 SRID.

的影响

要明确:我不能 100% 确定这些结论(我没有找到任何合适的文档),但是删除 coord_field 列然后设置 coord_field 如下:

coord_field = geoModels.PointField(srid=3857, blank=True, null=True)

..成功了。如果有人为我提供了清晰的答案,我仍然会很高兴阅读它!