【问题标题】:Why is nothing being saved when trying to update geoDjango Point objects?为什么尝试更新 geoDjango Point 对象时没有保存任何内容?
【发布时间】:2017-09-07 22:33:08
【问题描述】:


已解决:请参阅我自己的答案以获得解释。


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

我的 API 的一个功能是更新所有相关对象的特定 geoDjango Point 字段,这要归功于我的模型的专用方法 (这对于 EDIT 1 来说毫无用处,见下文)。

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

请参阅EDIT 2,我发现这个问题是 geoDjango Point 对象特有的(其他一切都按预期更新)。

下面是我的模型:

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

newLongnewLat 是通过 Google Maps API 生成的。 由于 Google Maps 似乎正在使用 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()

但是当尝试再次执行我的脚本(或者只是尝试使用我的新值属性)时,我只能观察到没有任何内容保存到数据库中(它仍然是printlocation.coord_field.srid 的旧值Locationobjects)。

我的脚本是如何执行的:

python manage.py shell
exec(script.py)

如果我调用了两次我的脚本,这里是以下回溯(只有一个对象可以理解):

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 向我指出,已经有一个函数可以更改 SRIDPoint 对象:transform
Location.objects.get(pk=pk).transform(3857) # define a new value of SRID

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


第二次编辑:我经历了很多痛苦才明白这是不是 save 方法不起作用!实际上,如果我尝试更新 MyAppModel 的“临时”数据字段,一切正常并按预期更新。真正的问题只是我的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 时确实遇到了麻烦,因此我会更新我的问题的标题!

【问题讨论】:

  • 请显示不工作的确切代码。我不确定你的表现是否足以说明问题所在。
  • newLongnewLatnewSRID 等从何而来?您如何验证没有任何变化?
  • 感谢您的回答,抱歉@Sayse 在您撰写评论时我正在编辑我的帖子!我真正想要改变的是我的观点。这就是我试图通过脚本显示的内容,以检查该值是否已有效更新。 newLong、newLat 由 GoogleMaps API 计算,但 newSRID 是手动指定的(我希望与 Gmaps 相同,即 3857,而 geoDjango 默认为 4326)。这样做的目的是找出为什么通过 django 进行的距离计算与 googlemaps 的计算不一致。

标签: python django google-maps-api-3 gis geodjango


【解决方案1】:

基于这个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 提供了关于cmets 的说明,他需要计算球面距离。我在这里发了一个帖子:How to calculate 3D distance (including altitude) between two points in GeoDjango

【讨论】:

  • transform 方法是我不知道的一件好事!即使它没有回答我的问题,感谢您的提示,我肯定会使用它而不是我的自定义函数。无论如何,由于following geoDjango doc,我认为我得到了不连贯的距离计算:> GEOS 距离计算是线性的——换句话说,即使 SRID 指定了地理坐标系,GEOS 也不执行球面计算。我>
  • @KrazyMax 我假设您的 srid 没有更新...我将添加一个对您有帮助的链接。
  • 嗯,有两件事:SRID 实际上没有更新到数据库中(Point 对象已经存在,但之后没有修改它们的 SRID)。然后,我并不是特别想用具有高度的Point 来计算距离(在 2D 中工作就可以了)。我的问题是,即使 PointAPointBlatlong 是在 Gmaps API 中定义的,PointA.distance(PointB) 返回的结果与我在 Gmaps 网站上得到的结果略有不同:实际距离为 459 公里,而实际距离为 388 公里!所以,仍在调查那个奇怪的结果......今晚会尝试一下你的 calc 函数!
【解决方案2】:

已解决:我的结论是,一旦您指定了一个Point 中的SRID,以后就不能再更改了。即使transform 方法也不会改变SRID,而只会进行一些就地的转换,而不会改变你的Point 的原始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)

.. 成功了。如果有人对我有明确的答案,我仍然会很感激阅读!

【讨论】:

    猜你喜欢
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-12
    相关资源
    最近更新 更多