mysql(MYISAM)でGeoDjango
djangoで位置情報を使うためにはGeoDjangoという仕組みを使うと良いらしい。
GeoDjango | Django documentation | Django
この機能をフルで使う為にはデータベースをPostgreSQLにしなければならないのだが、簡単な機能であればmysqlでも大丈夫。
やり方
settings.py
INSTALLED_APPSに'django.contrib.gis'を追加する
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.gis', )
DATABASES設定のENGINEを'django.contrib.gis.db.backends.mysql'に変更。
※'django.db.backends.mysql'では無いので注意
OPTIONSの部分でストレージエンジンをMYISAMに変更。
mysql5.6の時点ではMYISAMでないとGEOMETRY型(BLOB型)の列にスペシャルインデックスを貼る事ができない。
※innodbでは貼れない
DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.mysql', 'NAME': 'dbname', 'USER': 'root', 'PASSWORD': '', 'HOST': '127.0.0.1', 'PORT': '', 'OPTIONS': { "init_command": "SET storage_engine=MYISAM", } } }
models.py
モデルの作成例。
ポイントは継承先とマネージャをデフォルトのものから変更する事。
from django.contrib.gis.db import models # Create your models here. class GeoDataLog(models.Model): latlng = models.GeometryField(spatial_index=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) objects = models.GeoManager()
使い方
insert
point = Point(float(lat), float(lng)) GeoDataLog.objects.create(latlng=point)
select
普通にマネージャインスタンスからクエリセットを作って、とか出来なくはないが、 位置情報を使った複雑なクエリを発行したいなら、生のsqlで取るのが良さそう。
下記は指定の位置から緯度経度+-{latlng_range}内の短形領域内で指定の位置から近いデータを抽出する為のサンプル
※SQLインジェクションには十分注意して下さい!
sql = """ SELECT id AS id, GLength( GeomFromText( CONCAT( 'LineString({lat} {lng},', X(latlng), ' ', Y(latlng), ')' ) ) ) AS length_km, X(latlng) AS lat, Y(latlng) AS lng FROM geodata_geodatalog WHERE MBRContains( GeomFromText( Concat( 'LineString(', {lat} + {latlng_range}, ' ', {lng} + {latlng_range}, ',', {lat} - {latlng_range}, ' ', {lng} - {latlng_range}, ')' ) ), latlng ) HAVING length_km < {length_limit_km} ORDER BY length_km """.format( lat=lat, lng=lng, latlng_range=latlng_range, length_limit_km=length_limit_km ) cursor = connection.cursor() cursor.execute(sql) cursor.fetchall()