【问题标题】:How to bulk update a geom field based on lat/long?如何批量更新基于纬度/经度的几何字段?
【发布时间】:2020-09-28 22:38:28
【问题描述】:

我首先通过一个简单的 for 循环尝试了一个基本的实现,如下所示。它可以工作,但由于有 10k 条记录,需要的时间太长。

panoramas = Panorama.objects.all()
for panorama in panoramas:
    panorama.geo_location = Point([panorama.longitude, panorama.latitude])
    panorama.save()

基于Django的更新方法,然后我尝试了这样的事情:

geo_location = Panorama.objects.all().update(
    geo_location=fromstr(f'POINT({longitude} {latitude}', srid=4326)
)

这不起作用,因为我试图让 Django 为每条记录挑选纬度/经度并根据这两个字段更新 geo_location 但 django 不知道经度或纬度是什么。

有没有一种方法可以使用 update() 来实现?

【问题讨论】:

    标签: django python-3.x postgresql postgis geodjango


    【解决方案1】:

    在更新操作中使用数据库中的值正是 ORM F-expressions 的用途。

    在文档中的示例中,

    这个:

    reporter = Reporters.objects.get(name='Tintin')
    reporter.stories_filed += 1
    reporter.save()
    

    可以去这个:

    reporter = Reporters.objects.filter(name='Tintin')
    reporter.update(stories_filed=F('stories_filed') + 1)
    

    得益于拉取stories_filed + 1 并在数据库中运行其操作(添加)。


    PostGIS SQL 中的具体示例(未经测试):

    UPDATE
        panorama
    SET
        geom = ST_SetSRID(
            ST_Point(panorama.longitude, panorama.latitude),
            4326
        )
    FROM
        panorama
    ;
    

    参考资料: PostGIS ST_Point,PostgreSQL UPDATE

    【讨论】:

    • 虽然使用 F 表达式会引发错误:为点初始化提供的参数无效这是我尝试过的:geo_location = Panorama.objects.all().update(geo_location=Point(F('longitude'), F('latitude'), srid=4326))
    • @CLINTONBRAGANZA,嗯,我没有考虑点创建本身。我想知道某处是否有 GeoDjango 特定的文档。我的意思是,正如你所拥有的,Point 是一个 GEOS Python 类,而 F 表达式代表一些 SQL,它们将在数据库中被替换。老实说,原始 PostGIS SQL(或您的数据库风格)可能是最简单的,因为这可能是每个数据集操作一次。在这里,ORM 并不重要。在创建/更新几何字段之后,稍后使用 ORM 模型仍然有用。我会用一些 SQL 更新我的答案。
    【解决方案2】:

    想出了如何以优化的方式批量更新geom 字段。将每条记录单独保存在循环中需要很长时间(如预期的那样),因此需要使用 django 的 bulk_update() 方法。 Django bulk_update documentation

    panoramas = Panorama.objects.all()
    for panorama in panoramas:
         panorama.geo_location = Point(panorama.longitude, panorama.latitude, srid=4326)
    Panorama.objects.bulk_update(panoramas, ['geo_location'])
    

    【讨论】:

    • 通过 .update 和 F 表达式来做这件事仍然更快更干净。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 2014-12-03
    • 2017-06-16
    • 1970-01-01
    相关资源
    最近更新 更多