如何基于经纬度过滤Geodjango数据

4

我有一个应用程序,一直在存储经度和纬度,现在我想将其与Geodjango集成,该应用程序的样式如下。

class Location(models.Model):
    #other fields here
    lat = models.CharField(blank=True, max_length=100)
    lng = models.CharField(blank=True, max_length=100)

现在我想根据距离过滤位置,比如说,过滤所有距离 pk = 1 的位置 1 公里远的地方,使用 django.contrib.gis.measure 中的 D 和 GEOSGeometry 进行过滤,或者我应该重构模型,使用点代替经度和纬度,这样我就可以像这样做:

Location.objects.filter(point__dwithin=(D(km=5)))

有任何建议和推荐都可以。

2个回答

5

模式迁移

时光倒流到2016年,我们在Django中内置了迁移工具,你不再需要使用South。现在只需要两个迁移步骤,而不是三个。

第一步:更改模型。

class Location(models.Model):
    #other fields here
    lat = models.CharField(blank=True, max_length=100)
    lng = models.CharField(blank=True, max_length=100)

    point = models.PointField(null=True)

步骤二:创建迁移。
./manage.py makemigrations

数据迁移

这是第三个步骤,涉及编辑上面创建的迁移文件,查看操作部分并添加。

migrations.RunSQL('''UPDATE myapp_location SET `point` = Point(lat,lng)''')

这个查询是针对mysql的。如果您使用PostGis,则查询将为:
migrations.RunSQL('''UPDATE myapp_location SET "point" = ST_MakePoint(lng,lat)''')

请注意,postgis的格式为lng,lat
请注意,这是一个单一查询,并且应该能够快速执行。如果您有一百万条记录并且需要逐行迭代更新它们,那么将意味着一百万个查询!
步骤4:./manage.py migrate 步骤5:从模型中删除lat、lng列。
步骤6:./manage.py makemigrations 步骤7:./manage.py migrate

2
我在实现你上面的SQL查询时遇到了错误,它引发了 django.db.utils.DataError: Geometry SRID (0) does not match column SRID (4326) 的错误。 我通过以下方式解决了这个问题 migrations.RunSQL('''UPDATE myapp_location SET point = ST_SetSRID(ST_MakePoint(llng,lat),4326)''') - jbacker

3

使用South...需要进行3次迁移才能解决此问题。(链接:如何安装South

1)添加一个名为pointPointField

from django.contrib.gis.db import models  <-- NEW

# ...

class Location(models.Model):
    #other fields here
    lat = models.CharField(blank=True, max_length=100)
    lng = models.CharField(blank=True, max_length=100)

    point = models.PointField(null=True)  <-- NEW

2) 自动执行schemamigration

patrick@localhost:~$ python manage.py schemamigration my_app_name --auto

3)执行自定义的 datamigration,在现有的 CharField 属性中为每个元素创建一个点。

patrick@localhost:~$ python manage.py datamigration my_app_name latlng_to_point

编辑由datamigration管理命令创建的文件:

# my_app_name/migrations/0034__latlng_to_point.py

from django.contrib.gis.geos import Point

# ...

class Migration(DataMigration):

    def forwards(self, orm):
        "Write your forwards methods here."
        # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."
        for location in orm['my_app_name.Location'].objects.all():
            location.point = Point(float(location.lng), float(location.lat), srid=4326)
            location.save()

    def backwards(self, orm):
        "Write your backwards methods here."
        for location in orm['data.Location'].objects.all():
            location.point = None
            location.save()

4) 从你的模型中删除CharField并移除null=True(如果你想要这样做):

class Location(models.Model):
    # other fields here
    # DELETED lat = models.CharField(blank=True, max_length=100)
    # DELETED lng = models.CharField(blank=True, max_length=100)

    point = models.PointField(null=False)  <-- NEW: null=False

5) 自动创建另一个模式迁移

patrick@localhost:~$ python manage.py schemamigration my_app_name --auto

6)成功运行迁移!这时候对数据库等进行了更改。

patrick@localhost:~$ python manage.py migrate my_app_name

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接