diadia

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

geodjangoのメモ

 

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

from django.contrib.gis.db import models

を使うこと。

https://docs.djangoproject.com/en/2.2/ref/contrib/gis/model-api/#module-django.contrib.gis.db.models

同様にadmin.pyでもデフォルトのfrom django.contrib import adminを使わずに

from django.contrib.gis import admin

を使うことでadmin画面で空間データの入力が可能になる。

テンプレートについて

djangoのいつも通りにtemplate書いてview書いてもgeometry型のデータは文字でしか表示されない。つまりテンプレートに表示させるには何らかの処理が必要になる。template系についての情報を見つけた。もしかしてこれを使えばよいのかも!

https://medium.com/@h4k1m0u/displaying-a-map-in-a-django-webapp-2-3-develop-a-gis-webapp-with-geodjango-c831522ccf79

この記事によるとブラウザでデータをマップにプロットする場合にはdjango leafletを使う、と書いてある。leafletは1javascriptのライブラリのようでそのdjnagoバージョンらしい。
djnago leafletのドキュメント:
https://django-leaflet.readthedocs.io/en/latest/

インストール

pip install django-leaflet

settings.pyの編集

INSTALLED_APPS = [
    ...
    'leaflet',
    ]

テンプレート上での使い方

sample_template
{% load leaflet_tags %}
{% leaflet_css %}
{% leaflet_js %}


<h1>list</h1>
{{ object.point.x }}<br />
{{ object.point.y }}<br />
{% leaflet_map "main" callback="map_init_basic" %}


<script type="text/javascript">
    function map_init_basic(map, options) {
        var lon = "{{ object.point.x }}";
        var lat = "{{ object.point.y }}";
        #マップの拡大率を調整
        map.setView([lat, lon], 18);
        #地図に座標点をプロットする lon,latではなくlat,lonの順
        L.marker([lat, lon]).addTo(map);
        
    }	
</script>    

pointを複数表示させる方法(ListView)

views.pyはいつもどおりデータオブジェクトをリスト表示させるロジックを書けば良い。templateをgeodjango仕様にすればpointを複数リスト表示することができる。

sample_template
{% load leaflet_tags %}
{% leaflet_css %}
{% leaflet_js %}


<h1>list</h1>

{% leaflet_map "main" callback="map_init_basic" %}


<script type="text/javascript">
    function map_init_basic(map, options) {
        {% for object in objects %}
        var lon = "{{ object.point.x }}";
        var lat = "{{ object.point.y }}";
        #マップの拡大率を調整
        map.setView([lat, lon], 10);
        #地図に座標点をプロットする lon,latではなくlat,lonの順
        L.marker([lat, lon]).addTo(map);
        {% endfor %}
        
    }	
</script>    

javascriptのscriptタグ内でもdjangoのテンプレート制御構文を使うことができるようだ。これを使えばデータオブジェクトを全て地図上に表示することができる。

次にpointをクリックしたらデータ詳細が表示されるようにするには

地図上に位置情報をプロットするだけではなくて、マーカーをクリックしたらその他のプロパティを表示したい。これには.bindPopup()メソッドを用いれば良いようだ。
参考:https://qiita.com/amagasu1234/items/baf15da6655b74b4723a#%E3%81%BE%E3%81%9A%E3%81%AF%E5%8D%98%E7%B4%94%E3%83%9E%E3%83%BC%E3%82%AB%E3%83%BC%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%99

  sample_template
{% load leaflet_tags %}
{% leaflet_css %}
{% leaflet_js %}


<h1>list</h1>

{% leaflet_map "main" callback="map_init_basic" %}


<script type="text/javascript">
    function map_init_basic(map, options) {
        {% for object in objects %}
        var lon = "{{ object.point.x }}";
        var lat = "{{ object.point.y }}";
        #マップの拡大率を調整
        map.setView([lat, lon], 10);
        #地図に座標点をプロットする lon,latではなくlat,lonの順
        L.marker([lat, lon]).bindPopup("{{ object.user_name }}").addTo(map);
        {% endfor %}
        
    }	
</script>   

f:id:torajirousan:20190915131850p:plain

user_nameの表示ができた

 

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

Distance Queriesというものがあるようだ。これでできるか?
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/db-api/#distance-queries

  • distance_lt
  • distance_lte
  • distance_gt
  • distance_gte
  • dwithin

distance_lt:ルックアップジオメトリからジオメトリフィールドまでの距離が指定された距離値よりも小さいモデルを返します。
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/geoquerysets/#distance-lt

distance_lte:ルックアップジオメトリからジオメトリフィールドまでの距離が指定された距離値以下であるモデルを返します。
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/geoquerysets/#distance-lte

distance_gt:ルックアップジオメトリからジオメトリフィールドまでの距離が、指定された距離値よりも大きいモデルを返します。
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/geoquerysets/#distance-gt

distance_gte:ルックアップジオメトリからジオメトリフィールドまでの距離が、指定された距離値以上であるモデルを返します。
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/geoquerysets/#distance-gte

dwithin:ルックアップジオメトリからジオメトリフィールドまでの距離が互いに指定された距離内にあるモデルを返します。 ターゲットジオメトリが投影システムにある場合にのみ、距離オブジェクトを提供できることに注意してください。 地理的なジオメトリの場合、ジオメトリフィールドの単位(WGS84の度数など)を使用する必要があります。
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/geoquerysets/#dwithin

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

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

models.GeoManager()について

https://stackoverflow.com/questions/47690134/django-has-no-attribute-geomanager-issue
https://docs.djangoproject.com/en/2.0/releases/2.0/#features-removed-in-2-0

どうやらGeoManager()はdjango2.0以降では使われていないようだ。

https://docs.djangoproject.com/en/2.2/ref/contrib/gis/functions/