diadia

興味があることをやってみる。自分のメモを残しておきます。

geodjango実装メモ(修正版)

コンテンツ

  1. PointField等のGeo系特有のFieldを使うには?
  2. admin(管理ページ)でGeoデータを編集するためには?
  3. geometry型のデータをどのように画面に表示するか?
  4. django leafletの使い方
  5. 半径10km以内のpointのみを表示するにはどうすれば実現できるか?
  6. models.GeoManager()について
  7. wktを使ってオブジェクトをどう作成するのか?

留意点

このページに記録しているのはgeodjangoの内容が主であり、djangoOSMを表示するためのjavascriptライブラリleafletやdjangoサードパーティモジュールdjango leafletを使う際のメモは別ページに記載する。

1. PointField等のGeo系特有のFieldを使うには?

models.pyでpointを使う場合はmodels.PointFieldを使う。しかしデフォルトの from django.db import models にはPointFieldがない。

from django.contrib.gis.db import models

上記を使うとPointFieldを始めとしたgeometry型のデータを格納することができる。

Geo系特有のFieldをModelに導入する際のサンプル資料

GeoDjango Model API | Django documentation | Django

2. admin(管理ページ)でGeoデータを編集するためには?

adminでも他のモデルインスタンスと同じようにGeoデータを編集する事ができる。
これも同様にadmin.pyでデフォルトのfrom django.contrib import adminを使わない。

from django.contrib.gis import admin

上記のadminモジュールを使うことでadmin画面で空間データの入力が可能になる。 注意点としては上記のadminのインポートは、admin.pyに使うことはもちろん、urls.pyにも使う点だ。 デフォルトで生成さるproject用のurls.pyにはfrom django.contrib import adminが使ってある。つまり、これも修正すること。

from django.contrib.gis import admin # これに変更すること
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('maps/', include(maps.urls)),
    ]

3.geometry型のデータをどのように画面に表示するか?

普段どおり書くと...

いつも通りにdjangoのtemplate,viewを書いてもgeometry型データは文字としてしか表示されない。
つまりテンプレートに表示させるには何らかの処理が必要になる。それが何かを明らかにする必要がある。

ブラウザでGeoデータをマッピングするには

ブラウザでデータをマップにプロットする場合にはdjango leafletを使う。
そもそもleafletはjavascriptのライブラリのようである。django leafletはそのdjnagoバージョンらしい。

マッピングするにはdjango leafletが必要だ!という旨の資料

Displaying a map in a Django Webapp (2/3): Develop a GIS webapp with GeoDjango

django leafletのドキュメント

Welcome to Django Leaflet’s documentation! — Django Leaflet 0.20 documentation

4. django leafletの使い方

内容が結構あるので以下に別途作成した。
django leaflet の使い方メモ - diadia

5. 半径10km以内のpointのみを表示するにはどうすれば実現できるか?

postgisであれば、そのSQLを実行すればそのデータを抽出できる。
大体postgisSQLの書き方とGeodjangoのクエリメソッドは似ていることがあるのでそこから見当をつけられる。

Distance Queriesがある。

GeoDjango Database API | Django documentation | Django

クエリメソッド 説明 URL
distance_lt ルックアップジオメトリからジオメトリフィールドまでの距離が指定された距離値よりも小さいモデルを返します。 GIS QuerySet API Reference | Django documentation | Django
distance_lte ルックアップジオメトリからジオメトリフィールドまでの距離が指定された距離値以下であるモデルを返します。 GIS QuerySet API Reference | Django documentation | Django
distance_gt ルックアップジオメトリからジオメトリフィールドまでの距離が、指定された距離値よりも大きいモデルを返します。 GIS QuerySet API Reference | Django documentation | Django
distance_gte ルックアップジオメトリからジオメトリフィールドまでの距離が、指定された距離値以上であるモデルを返します。 GIS QuerySet API Reference | Django documentation | Django
dwithin ルックアップジオメトリからジオメトリフィールドまでの距離が互いに指定された距離内にあるモデルを返します。 ターゲットジオメトリが投影システムにある場合にのみ、距離オブジェクトを提供できることに注意してください。 地理的なジオメトリの場合、ジオメトリフィールドの単位(WGS84の度数など)を使用する必要があります。 GIS QuerySet API Reference | Django documentation | Django

メモ:https://codeday.me/jp/qa/20190526/901886.html

https://docs.djangoproject.com/en/2.2/ref/contrib/gis/db-api/#distance-lookups

6. models.GeoManager()について

どうやらGeoManager()はdjango2.0以降では使われていないようだ。 Spatial Lookupsを使うこととある。

GeoManagerはdjango2.0以降使われないことに言及した資料

Django has no attribute 'GeoManager' issue - Stack Overflow

django2.0で削除された機能を示すドキュメント

Django 2.0 release notes | Django documentation | Django

7. wktを使ってオブジェクトをどう作成するのか?

WKT, HEX, WKB, GeoJSONを使ってGEOSGeometryオブジェクトを作成することができる。例えばwktならばGEOSGeometryの引数としてwktを使うだけで生成する事ができる。

from django.contrib.gis.geos import GEOSGeometry
point = GEOSGeometry('POINT(5 23)') # WKT

ただし、sridは上記の場合は設定されないので別途自分で設定する必要がある。

print(point.srid)
>>>None
point = GEOSGeometry('POINT(5 23)', srid=4326)

#または
point = GEOSGeometry('POINT(5 23)') 
point.srid = 4326

#または
point = GEOSGeometry("SRID=4326;POINT(5 23)") 

GEOSGeometryオブジェクトは、そのままgeogjangoの操作に利用することができる。 例えばgeogjangomのあるモデルオブジェクトのポリゴン内にGEOSGeometryオブジェクトのPOINTが含まれるかなんてことができる。

point = GEOSGeometry('POINT(5 23)', srid=4326)
city = City.objects.get(name="鹿児島")
city_polygon = city.geom
print(city_polygon.contains(point))

>>>False

geodjangoのfieldに対しそのまま使用する事ができるか?

ジオメトリ型データを作成する方法を示す資料

GEOS API | Django ドキュメント | Django