GeoDjangoでWeb地図をつくろう!

この記事は,インフラデータチャレンジ(IDC2018)における作品応募に向けた 提供データの特徴や活用方法のヒントについて,実行委員等がリレー形式で紹介 するものです.今回は,Django Girlsの榎本さんにインフラデータチャレンジのデータセットとして提供されている「水難事故データ(河川財団)」を使ったチュートリアルをご紹介いただきます.
募集要項等は,Webサイトをご覧ください
http://jsce-idc.jp/

GISで分析したり可視化したものを、Webアプリケーションにして発信したい!と思い、Python製WebフレームワークのDjangoを使ってみました。


Django Girlsの榎本です。「Django Girls」は、PythonのWebアプリケーションフレームワーク"Django"(ジャンゴ) を使って、女性を対象とした初心者向けプログラミング講座を実施しています。Tech業界あるいはPythonユーザーの多様性と女性の活躍推進を目指し、女性にプログラミングを楽しんでもらうことを目的としている、グローバルな非営利コミュニティーです。

今回は、Djangoを使って、地理空間情報を扱ったWebアプリケーションに挑戦してみたいと思います。

  1. プロジェクトを作成する
  2. アプリケーションをつくる
  3. データをインポートして、Django Adminで地図を表示する

という流れです。
管理画面で位置情報のデータを表示するところまで、やってみます。
(なお、FOSS4G で発表した内容をもとにしています。)


Djangoってなに?

Django(じゃんご)は、Python製のWebフレームワークの1つです。
管理画面がサクッとできてしまうのがステキです。
そして、DjangoのGeoDjangoモジュールを使ってPostGISを扱うことができます。


1.プロジェクトを作成する

環境構築

Pythonは3系を使います。

$ python -V
Python 3.6.3

まず、 virtualenvで仮想環境を作りましょう

$ mkdir geodjango && cd geodjango
# myenv という名前の仮想環境をつくる
geodjango$ virtualenv --python=python3 myenv
# 作成したmyenvという仮想環境をアクティベートする
geodjango$ source myenv/bin/activate

pip で Django をインストールします。

(myenv)$ pip install Django==2.0.3

プロジェクトを作成する

geodjangoという名前のプロジェクトを作成します。

(myenv)$ django-admin startproject geodjango

すると、このようなディレクトリ構成になっています。

geodjango   <-- プロジェクトのルート
├── manage.py <-- プロジェクトの管理用のスクリプト
└── geodjango <-- プロジェクト設定
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

設定ファイル geodjango/settings.py を編集して、言語やタイムゾーンを変更しておきます。

# geodjango/settings.py
# LANGUAGE_CODE = 'en-us’
LANGUAGE_CODE = ‘ja’
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'

ここまでをやってみましょう。

2.アプリケーションを作成する

アプリケーションを作成する

map というアプリケーションを作ります。

(myenv)$ cd geodjango
(myenv)$ python manage.py startapp map

geodjango/settings.py を編集し、データベースの設定がデフォルトではSQLiteになっているので、PostGISに変えます。そして、アプリケーションを追加します。

# geodjango/settings.py
# データベースの設定をする
DATABASES = {
'default’: {
# ‘ENGINE’: ‘Django.db.backends.sqlite3’
# ‘NAME’: os.path.join(BASE_DIR, ‘db.sqlite3’),
'ENGINE': 'django.contrib.gis.db.backends.postgis’,
'NAME': '<database>’,
'USER': '<database-user>’,
},
}
# アプリケーションを有効化する
INSTALLED_APPS = [
'django.contrib.admin’,
'django.contrib.auth’,
:
‘django.contrib.gis’, # gis を追加
‘map’, # 先ほど作成したアプリケーションを追加
]

管理ユーザーを作成します。

(myenv)$ python manage.py migrate
(myenv)$ python manage.py createsuperuser

開発サーバーを起動する

(myenv)$ cd geodjango
(myenv)$ python manage.py runserver
開発サーバーを起動して、確認
管理画面にログイン


3.データをインポートする

ここで、インフラデータチャレンジの提供データである水難事故データをインポートしてみましょう。

水難事故データ
データ提供:
公益財団法人 河川財団
データの内容:河川財団で収集した2005年から2016年までの1,845件の
 水難事故マップ公表デー タ。事故年月、都道府県名・河川名、事故概要、緯度経度、位置情報の精度

suinanjiko.geojson はこんなデータです。

{   "type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [ 131.491361 ,34.186589 ]
},
"properties": {
"no":1,
"ym":200504,
"pref":"山口県",
"river":"椹野川",
"jiko":"河原で遊んでいた幼児が増水した川に転落",
"accurate":"01.ほぼ特定”
}
},
:

geojsonファイルのモデル構造を調べる

$python manage.py ogrinspect <データファイル> <モデル名> で、ファイルのモデル構造を調べることができます。

(myenv)$ python manage.py ogrinspect --srid=4326  jiko.geojson  Suinanjiko
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Suinanjiko(models.Model):
no = models.IntegerField()
ym = models.IntegerField()
pref = models.CharField(max_length=0)
river = models.CharField(max_length=0)
jiko = models.CharField(max_length=0)
accurate = models.CharField(max_length=0)
geom = models.PointField(srid=4326)

ogrinspectコマンドで、このようにモデル構造がズラズラっとでてきます。これをコピーして、 models.py に貼り付けます。 
文字列のmax_length=0になっているので変更します。

from django.contrib.gis.db import models
class Suinanjiko(models.Model):
no = models.IntegerField()
ym = models.IntegerField()
pref = models.CharField(max_length=50)
river = models.CharField(max_length=50)
jiko = models.CharField(max_length=256)
accurate = models.CharField(max_length=256)
geom = models.PointField(srid=4326)
def __str__(self):
return self.jiko

データベースの更新をするために、マイグレーションファイルを作成します。

(myenv)$ python manage.py makemigrations

モデルの変更内容をデータベースに反映します。

(myenv)$ python manage.py migrate

データインポートするスクリプトを作成する

データをインポートするload_suinanjiko.py というファイルを作成します

import os
from django.contrib.gis.utils import LayerMapping
from map.models import Suinanjiko
# Modelとファイルのカラムのマッピング
mapping = {
'no' : 'no’,
'ym' : 'ym’,
:
'geom' : 'POINT’,
}
# ファイルパス
geojson_file = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'data’, 'suinanjiko.geojson’))
# 実行
def run(verbose=True):
lm = LayerMapping(Suinanjiko, geojson_file,
mapping,transform=False, encoding='UTF-8’)
lm.save(strict=True, verbose=verbose)

Djangoのシェルを起動して、load_suinanjiko.pyを実行します。

(myenv)$ python manage.py shell
>>> from map import load_Hokkaido
>>> load_suinanjiko.run()

Saved : ~~~~
Saved : ~~~~
:
>>> exit()


管理画面の設定を変更する

map/admin.py

from django.contrib.gis import admin
from map.models import Suinanjiko
#背景地図をOpenStreetMapにする
admin.site.register(Suinanjiko, admin.OSMGeoAdmin)

geodjango/urls.py

# from django.contrib import admin
from django.contrib.gis import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]

(myenv)$python manage.py runserver で開発サーバーを起動して、管理画面でインポートしたデータを確認してみましょう。



というわけで(?)、このような水難事故マップができました。



Special Thanks !!

Django Girls のみなさん
GeoDjangoではじめる地理空間情報入門」小俣さん
FOSS4G実行委員のみなさん