PostGISとGeoDjangoを使ってLeafletでGeoJSON Tile Layerを表示してみる(2) – GeoDjango経由でShapefileをインポートする –

前回でようやくPostGISとGeoDjangoのインストールが完了しましたので、それでは早速Djangoを使ってみましょう。ただ、今回はDjangoと言っても、GeoDjangoなので、できればデータがあったほうがいいですよね。ということで、国民の味方、国土交通省の国土数値情報を使わせて頂くことにしましょう。

データの準備

データの入手

以下のページから「行政区域」をダウンロードして利用させて頂きました。

国土数値情報 ダウンロードサービス

私は全国(N03-14-140401)で試していますが、必要に応じて各都道府県版でも動作上問題はありませんのでお好きなモノを選択ください。

Djangoアプリをつくる

先に申し上げておきますが、Django使うの初めてです。ですので色々イケてないやり方や説明に不備があるかとおもいますが、とりあえず動きはするので信じてついてきてください。

プロジェクト作成

任意のディレクトリで以下コマンドを叩くと、次のようなファイルが自動生成されます。

$ django-admin.py startproject geodjango
$ tree -c geodjango
geodjango
├── geodjango
│   ├── __init__.pyc
│   ├── settings.pyc
│   ├── settings.py
│   ├── __init__.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

アプリ作成

先程作成したgeodjangoディレクトリに移動してアプリを「demo」という名前で作成します。するとアプリ名のディレクトリが作成され、作成したディレクトリ配下に次のようなファイルが自動生成されます。

$ cd geodjango/
$ python manage.py startapp demo
$  ls -F
demo/  geodjango/  manage.py*
$ tree -c demo
demo
├── __init__.py
├── admin.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

なお、一つのdjangoプロジェクト内に複数アプリを作成してURLマッピングで同時に利用できるので、ここでいうアプリはWebアプリの一つのモジュールなイメージっぽいです。

GeoDjango用にプロジェクト設定を変更する

Djangoのプロジェクト設定を編集します。なお、以下の日本語コメントをそのまま貼り付けると文字コードでエラーになるので除去するかファイルの行頭に「# -*- coding: utf-8 -*-」を追加してください。

$  vi geodjango/settings.py
# postgisの設定変更する
DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'geodjangodb',
        'USER': 'geodjango', # 前回作成DBユーザの名前
        'PASSWORD': '*****', # 前回作成DBユーザのパスワード
    }
}

# 以下の2行を追加
INSTALLED_APPS = (
    'django.contrib.gis', # 既存定義の最後に追加
    'demo',               # 既存定義の最後に追加
)
# 日本向けに変更(お好みで)
LANGUAGE_CODE = 'ja'     # 値を変更
TIME_ZONE = 'Asia/Tokyo' # 値を変更

Shapefileのインポート

先程ダウンロードして加工したデータ(Shapefile)をもとにモデルクラスを作成し、ShapefileのデータをDBにインポートします。ちょっと長いですがココが今回の一番重要なところです。

まずはdemo配下にdataディレクトリを作成します。

$ mkdir demo/data

上記ディレクトリにダウンロードしたzipファイル展開後のファイル一式をscp等で転送してください。

$ ls demo/data/
KS-META-N03-14_140401.xml  N03-14_140401.sbn  N03-14_140401.shx
N03-14_140401.dbf          N03-14_140401.sbx  N03-14_140401.xml
N03-14_140401.prj          N03-14_140401.shp

こんな種類のファイルがあればOKです。

1.Shapefileの頂点数を減らす

ダウンロードしてきたShapefileをそのまま利用するのでもいいのですが、ポリゴンの頂点数が多いのでそのまま扱うと地図表示の時などに重くなるので楽しくありません。今回は精度は特に考えずにサクサク試したいので、頂点数を減らしましょう。

$ cd demo/data
$ ogr2ogr N03-14_140401_Simply.shp N03-14_140401.shp -simplify 0.0001 -lco ENCODING=932

コマンドが完了すると以下のようなファイルが増えています。こちらが簡素化されたShapefileになります。

$ ls *Simply*
N03-14_140401_Simply.cpg  N03-14_140401_Simply.prj  N03-14_140401_Simply.shx
N03-14_140401_Simply.dbf  N03-14_140401_Simply.shp

2.Shapefileの構造確認

ここで、モデルクラスを定義するためにShapefileの構造を確認します。

$ ogrinfo N03-14_140401_Simply.shp
INFO: Open of `N03-14_140401_Simply.shp'
      using driver `ESRI Shapefile' successful.
1: N03-14_140401_Simply (Polygon)
$ ogrinfo -so N03-14_140401_Simply.shp N03-14_140401_Simply
INFO: Open of `N03-14_140401_Simply.shp'
      using driver `ESRI Shapefile' successful.

Layer name: N03-14_140401_Simply
Geometry: Polygon
Feature Count: 73274
Extent: (122.933665, 20.425127) - (153.986893, 45.557667)
Layer SRS WKT:
GEOGCS["GCS_JGD_2000",
    DATUM["Japanese_Geodetic_Datum_2000",
        SPHEROID["GRS_1980",6378137.0,298.257222101]],
    PRIMEM["Greenwich",0.0],
    UNIT["Degree",0.017453292519943295]]
N03_001: String (10.0)
N03_002: String (20.0)
N03_003: String (20.0)
N03_004: String (20.0)
N03_007: String (5.0)

3.モデルクラスの作成

今度は構造に合わせてモデルクラスを定義します。先程の出力結果を見ながら手動で作成してもいいのですが、自動で生成してみましょう(前回記事の修正前の段階でDB作成している場合は、ogrinspectで失敗します。申し訳ありませんが、以下のカスタマイズ後のものを貼り付けるか、DB削除後、修正後記事内容でひな形作成から行うようにお願いします)。

$ python manage.py ogrinspect --srid=4612 demo/data/N03-14_140401_Simply.shp Border  > demo/models.py
$ vi demo/models.py

こんな形で自動生成されています。

# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models

class Border(models.Model):
    n03_001 = models.CharField(max_length=10)
    n03_002 = models.CharField(max_length=20)
    n03_003 = models.CharField(max_length=20)
    n03_004 = models.CharField(max_length=20)
    n03_007 = models.CharField(max_length=5)
    geom = models.PolygonField(srid=4612)
    objects = models.GeoManager()

自動生成されたものをベースに修正します。

# -*- coding: utf-8 -*-
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models

class Border(models.Model):
    n03_001 = models.CharField(u'都道府県名', max_length=10)
    n03_002 = models.CharField(u'支庁名', max_length=20, blank=True)
    n03_003 = models.CharField(u'群・政令市名', max_length=20, blank=True)
    n03_004 = models.CharField(u'市区町村名', max_length=20, blank=True)
    n03_007 = models.CharField(u'行政区域コード', max_length=5)
    geom = models.PolygonField(srid=4612)
    objects = models.GeoManager()

    def __unicode__(self):
        return "%s_%s_%s(%s)" % (self.n03_001,self.n03_003,self.n03_004,self.n03_007)

    class Meta:
        verbose_name = u"行政区域"
        verbose_name_plural = u"行政区域一覧"

変更内容は以下のとおりです。

・日本語を扱うので公式チュートリアルの「__str__()」の代わりに「__unicode__()」を定義
・元データでは空白になるフィールドがあるので空白許容を追加
・各フィールドのフォームに用いられるラベルを追加
・管理画面用にMetaクラスを定義

4.DBにモデルを反映

作成したモデルからDBに各種テーブルを作成します。

$ python manage.py makemigrations
Migrations for 'demo':
  0001_initial.py:
    - Create model Border
$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: gis
  Apply all migrations: admin, demo, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying demo.0001_initial... OK
  Applying sessions.0001_initial... OK

本当に出来てるか念のため確認しましょう。

$psql geodjangodb -U geodjango
ユーザ geodjango のパスワード:****
psql (9.3.5)
"help" でヘルプを表示します.

geodjangodb=> \dt
                      リレーションの一覧
 スキーマ |            名前            |    型    |  所有者
----------+----------------------------+----------+-----------
 public   | auth_group                 | テーブル | geodjango
 public   | auth_group_permissions     | テーブル | geodjango
 public   | auth_permission            | テーブル | geodjango
 public   | auth_user                  | テーブル | geodjango
 public   | auth_user_groups           | テーブル | geodjango
 public   | auth_user_user_permissions | テーブル | geodjango
 public   | demo_border                | テーブル | geodjango
 public   | django_admin_log           | テーブル | geodjango
 public   | django_content_type        | テーブル | geodjango
 public   | django_migrations          | テーブル | geodjango
 public   | django_session             | テーブル | geodjango
 public   | spatial_ref_sys            | テーブル | postgres
(12 行)
geodjangodb=> \d demo_border
                                テーブル "public.demo_border"
   列    |           型           |                          修飾語
---------+------------------------+----------------------------------------------------------
 id      | integer                | not null default nextval('demo_border_id_seq'::regclass)
 n03_001 | character varying(10)  | not null
 n03_002 | character varying(20)  | not null
 n03_003 | character varying(20)  | not null
 n03_004 | character varying(20)  | not null
 n03_007 | character varying(5)   | not null
 geom    | geometry(Polygon,4612) | not null
インデックス:
    "demo_border_pkey" PRIMARY KEY, btree (id)
    "demo_border_geom_id" gist (geom)
geodjangodb=>\q

それっぽいのができてますね。

5.DBにデータを登録

テーブルができたので早速データを登録します。
インタラクティブにやってもいいですが、Shapefile投入用の処理を書きましょう。

$ vi demo/load.py
# -*- coding: utf-8 -*-
import os
from django.contrib.gis.utils import LayerMapping
from demo.models import Border

# モデルクラスとShapefileのカラムのマッピング
border_mapping = {
    'n03_001' : 'N03_001',
    'n03_002' : 'N03_002',
    'n03_003' : 'N03_003',
    'n03_004' : 'N03_004',
    'n03_007' : 'N03_007',
    'geom' : 'POLYGON',
}

# ロード対象のShapefile
border_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/N03-14_140401_Simply.shp'))

def run(verbose=True):
    lm = LayerMapping(Border, border_shp, border_mapping, transform=False, encoding='utf-8')
    lm.save(strict=True, verbose=verbose)

この関数を管理シェルで実行します。

$ python manage.py shell
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
Type "copyright", "credits" or "license" for more information.

IPython 2.3.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: from demo import load
In [2]: load.run()

# Saved: XXXX が出力される(登録件数分)
In [3]: exit

さて、ちゃんと登録されたかDBを見てみましょう。

$ psql geodjangodb -U geodjango
ユーザ geodjango のパスワード:****
psql (9.3.5)
"help" でヘルプを表示します.

geodjangodb=> select count(*) from demo_border;
 count
-------
 73274
(1 行)

geodjangodb=>\q

全国分なので73274件入りました。

さてこれでようやくデータ登録が完了したので、次回は管理画面を使ってデータを確認してみましょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*