Python 和 Django
空间数据库
PostgreSQL/MySQL/Oracle/SQLite
地理相关库
数据库 | 库依赖 |
---|---|
PostgreSQL | GEOS, GDAL, PROJ.4, PostGIS |
MySQL | GEOS, GDAL |
Oracle | GEOS, GDAL |
SQLite | GEOS, GDAL, PROJ.4, SpatiaLite |
软件 | 版本 |
---|---|
Python | 3.7.6 |
Django | 3.0.8 |
PostgreSQL | 12.3.1 |
PostGIS | 3.0.1 |
Geos | 3.8.1 |
Proj | 6.3.2 |
GDAL | 3.0.4 |
先安装PostgreSQL,安装完成后,提示运行Stack Builder.通过该工具安装PostGIS.
若Stack Builder扩展插件下载和安装失败,下载postgis-bundle-pg12x64-setup-3.0.1-3.exe
手动完成.
psycopg2是python模块提供的Python和PostgreSQL数据库之间的接口,执行
pip install psycopg2
OSGeo4W安装程序帮助安装GeoDjango所需的PROJ.4,GDAL和GEOS库.
selectpackages
列表中确保选择了GDAL,单击“下一步”后OSGEO4W_ROOT
和PYTHON_ROOT
以计算机实际位置为准,命令行下执行
set OSGEO4W_ROOT=C:\OSGeo4W
set PYTHON_ROOT=C:\Python3X
set GDAL_DATA=%OSGEO4W_ROOT%\share\gdal
set PROJ_LIB=%OSGEO4W_ROOT%\share\proj
set PATH=%PATH%;%PYTHON_ROOT%;%OSGEO4W_ROOT%\bin
reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "%PATH%"
reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v GDAL_DATA /t REG_EXPAND_SZ /f /d "%GDAL_DATA%"
reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PROJ_LIB /t REG_EXPAND_SZ /f /d "%PROJ_LIB%"
D:\>cd geodj
D:\geodj>mkdir venv
D:\geodj>virtualenv -p python.\ venv
created virtual environment CPython3.7.6.final.0-64 in 16109ms
creator CPython3Windows(dest=D:\geodj\venv, clear=False, global=False)
seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\xxx\AppData\Local\pypa\virtualenv)
added seed packages: pip==20.1.1, setuptools==49.2.0, wheel==0.34.2
activators BashActivator,BatchActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator
D:\geodj>.\venv\scripts\activate
(venv) D:\geodj>pip install django
Collecting django
Using cached Django-3.0.8-py3-none-any.whl (7.5 MB)
Collecting pytz
Using cached pytz-2020.1-py2.py3-none-any.whl (510 kB)
Collecting sqlparse>=0.2.2
Using cached sqlparse-0.3.1-py2.py3-none-any.whl (40 kB)
Collecting asgiref~=3.2
Using cached asgiref-3.2.10-py3-none-any.whl (19 kB)
Installing collected packages: pytz, sqlparse, asgiref, django
Successfully installed asgiref-3.2.10 django-3.0.8 pytz-2020.1 sqlparse-0.3.1
(venv) D:\geodj>django-admin startproject geodjango
(venv) D:\geodj>cd geodjango
(venv) D:\geodj\geodjango>python manage.py startapp world
# geodjango/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': '数据库名',
'USER': '用户名',
'PASSWORD': '密码',
'HOST': '127.0.0.1',
'PORT': '5432',
},
}
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis', # 添加
'world', # 添加
]
(venv) D:\geodj\geodjango>mkdir world\data
(venv) D:\geodj\geodjango>cd world\data
(venv) D:\geodj\geodjango\world\data>wget https://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
'wget' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
(venv) D:\geodj\geodjango\world\data>cd ..\..\
(venv) D:\geodj\geodjango>ogrinfo world\data\TM_WORLD_BORDERS-0.3.shp
INFO: Open of `world\data\TM_WORLD_BORDERS-0.3.shp'
using driver `ESRI Shapefile' successful.
1: TM_WORLD_BORDERS-0.3 (Polygon)
(venv) D:\geodj\geodjango>ogrinfo -so world\data\TM_WORLD_BORDERS-0.3.shp TM_WORLD_BORDERS-0.3
INFO: Open of `world\data\TM_WORLD_BORDERS-0.3.shp'
using driver `ESRI Shapefile' successful.
Layer name: TM_WORLD_BORDERS-0.3
Metadata:
DBF_DATE_LAST_UPDATE=2008-07-30
Geometry: Polygon
Feature Count: 246
Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)
Layer SRS WKT:
GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["latitude",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["longitude",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4326]]
Data axis to CRS axis mapping: 2,1
FIPS: String (2.0)
ISO2: String (2.0)
ISO3: String (3.0)
UN: Integer (3.0)
NAME: String (50.0)
AREA: Integer (7.0)
POP2005: Integer64 (10.0)
REGION: Integer (3.0)
SUBREGION: Integer (3.0)
LON: Real (8.3)
LAT: Real (7.3)
# geodjango/world/models.py
from django.contrib.gis.db import models
class WorldBorder(models.Model):
# Regular Django fields corresponding to the attributes in the
# world borders shapefile.
name = models.CharField(max_length=50)
area = models.IntegerField()
pop2005 = models.IntegerField('Population 2005')
fips = models.CharField('FIPS Code', max_length=2, null=True)
iso2 = models.CharField('2 Digit ISO', max_length=2)
iso3 = models.CharField('3 Digit ISO', max_length=3)
un = models.IntegerField('United Nations Code')
region = models.IntegerField('Region Code')
subregion = models.IntegerField('Sub-Region Code')
lon = models.FloatField()
lat = models.FloatField()
# GeoDjango-specific: a geometry field (MultiPolygonField)
mpoly = models.MultiPolygonField()
# Returns the string representation of the model.
def __str__(self):
return self.name
(venv) D:\geodj\geodjango>python manage.py makemigrations
Migrations for 'world':
world\migrations\0001_initial.py
- Create model WorldBorder
(venv) D:\geodj\geodjango>python manage.py sqlmigrate world 0001
BEGIN;
--
-- Create model WorldBorder
--
CREATE TABLE "world_worldborder" ("id" serial NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL, "area" integer NOT NULL, "pop2005" integer NOT NULL, "fips" varchar(2) NULL, "iso2" varchar(2) NOT NULL, "iso3" varchar(3) NOT NULL, "un" integer NOT NULL, "region" integer NOT NULL, "subregion" integer NOT NULL, "lon" double precision NOT NULL, "lat" double precision NOT NULL, "mpoly" geometry(MULTIPOLYGON,4326) NOT NULL);
CREATE INDEX "world_worldborder_mpoly_id" ON "world_worldborder"USING GIST ("mpoly");
COMMIT;
(venv) D:\geodj\geodjango>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, world
Running migrations:
Applying world.0001_initial... OK
Python
(venv) D:\geodj\geodjango>python manage.py shell
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import os
>>> import world
>>> world_shp = os.path.abspath(os.path.join(os.path.dirname(world.__file__),'data', 'TM_WORLD_BORDERS-0.3.shp'))
>>> from django.contrib.gis.gdal import DataSource
>>> ds = DataSource(world_shp)
>>> print(ds)
D:\geodj\geodjango\world\data\TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)
>>> print(len(ds))
1
>>> lyr = ds[0]
>>> print(lyr)
TM_WORLD_BORDERS-0.3
>>> print(lyr.geom_type)
Polygon
>>> print(len(lyr))
246
>>> srs = lyr.srs
>>> print(srs)
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9122"]],
AXIS["Latitude",NORTH],
AXIS["Longitude",EAST],
AUTHORITY["EPSG","4326"]]
>>> srs.proj4
'+proj=longlat +datum=WGS84 +no_defs'
>>> print(lyr.fields)
['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT']
>>> [fld.__name__ for fld in lyr.field_types]
['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger64', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal']
>>> for feat in lyr:
... print(feat.get('NAME'), feat.geom.num_points)
...
Antigua and Barbuda 48
Algeria 1241
Azerbaijan 871
Albania 337
......
Saint Barthelemy 14
Guernsey 18
Jersey 26
South Georgia South Sandwich Islands 338
Taiwan 363
>>> lyr[0:2]
[<django.contrib.gis.gdal.feature.Feature object at 0x000001A186CC9488>,
<django.contrib.gis.gdal.feature.Feature object at 0x000001A186CC9348>]
>>> feat = lyr[234]
>>> print(feat.get('NAME'))
San Marino
>>> geom = feat.go
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Feature' object has no attribute 'go'
>>> geom = feat.geom
>>> print(geom.wkt)
POLYGON ((12.415798 43.957954,12.450554 43.979721,12.453888 43.981667,12.4625 43.984718,12.471666 43.986938,
12.492777 43.989166,12.505554 43.988609,12.509998 43.986938,12.510277 43.982773,12.511665 43.943329,
12.510555 43.939163,12.496387 43.923332,12.494999 43.914719,12.487778 43.90583,12.474443 43.897217,
12.464722 43.895554,12.459166 43.896111,12.416388 43.904716,12.412222 43.906105,12.407822 43.913658,
12.403889 43.926666,12.404999 43.948326,12.408888 43.954994,12.415798 43.957954))
world/load.py
# world/load.py
import os
from django.contrib.gis.utils import LayerMapping
from .models import WorldBorder
world_mapping = {
'fips' : 'FIPS',
'iso2' : 'ISO2',
'iso3' : 'ISO3',
'un' : 'UN',
'name' : 'NAME',
'area' : 'AREA',
'pop2005' : 'POP2005',
'region' : 'REGION',
'subregion' : 'SUBREGION',
'lon' : 'LON',
'lat' : 'LAT',
'mpoly' : 'MULTIPOLYGON',
}
world_shp = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'data', 'TM_WORLD_BORDERS-0.3.shp'),
)
def run(verbose=True):
lm = LayerMapping(WorldBorder, world_shp, world_mapping, transform=False)
lm.save(strict=True, verbose=verbose)
(venv) D:\geodj\geodjango>python manage.py shell
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from world import load
>>> load.run()
Saved: Antigua and Barbuda
Saved: Algeria
Saved: Azerbaijan
Saved: Albania
Saved: Armenia
Saved: Angola
......
Saved: South Georgia South Sandwich Islands
Saved: Taiwan
(venv) D:\geodj\geodjango>python manage.py ogrinspect world\data\TM_WORLD_BORDERS-0.3.shp WorldBorder --srid=4326 --mapping --multi
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class WorldBorder(models.Model):
fips = models.CharField(max_length=2)
iso2 = models.CharField(max_length=2)
iso3 = models.CharField(max_length=3)
un = models.IntegerField()
name = models.CharField(max_length=50)
area = models.IntegerField()
pop2005 = models.BigIntegerField()
region = models.IntegerField()
subregion = models.IntegerField()
lon = models.FloatField()
lat = models.FloatField()
geom = models.MultiPolygonField(srid=4326)
# Auto-generated `LayerMapping` dictionary for WorldBorder model
worldborder_mapping = {
'fips': 'FIPS',
'iso2': 'ISO2',
'iso3': 'ISO3',
'un': 'UN',
'name': 'NAME',
'area': 'AREA',
'pop2005': 'POP2005',
'region': 'REGION',
'subregion': 'SUBREGION',
'lon': 'LON',
'lat': 'LAT',
'geom': 'MULTIPOLYGON',
}
(venv) D:\geodj\geodjango>python manage.py shell
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> pnt_wkt = 'POINT(-95.3385 29.7245)'
>>> from world.models import WorldBorder
>>> WorldBorder.objects.filter(mpoly__contains=pnt_wkt)
GDAL_ERROR 4: b'POINT(-95.3385 29.7245): No such file or directory'
GDAL_ERROR 10: b"Pointer 'hObject' is NULL in 'GDALGetDescription'.\n"
<QuerySet [<WorldBorder: United States>]>
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(12.4604, 43.9420)
>>> WorldBorder.objects.get(mpoly__intersects=pnt)
<WorldBorder: San Marino>
>>> from django.contrib.gis.geos import GEOSGeometry, Point
>>> pnt = Point(954158.1, 4215137.1, srid=32140)
>>> pnt = GEOSGeometry('SRID=32140;POINT(954158.1 4215137.1)')
>>> qs = WorldBorder.objects.filter(mpoly__intersects=pnt)
>>> print(qs.query)
SELECT "world_worldborder"."id", "world_worldborder"."name", "world_worldborder"."area", "world_worldborder"."pop2005", "world_worldborder"."fips", "world_worldborder"."iso2", "world_worldborder"."iso3", "world_worldborder"."un", "world_worldborder"."region", "world_worldborder"."subregion", "world_worldborder"."lon", "world_worldborder"."lat", "world_worldborder"."mpoly"::bytea FROM "world_worldborder" WHERE ST_Intersects("world_worldborder"."mpoly", ST_Transform(ST_GeomFromEWKB('\001\001\000\000 \214}\000\0003333\\\036-AfffFX\024PA'::bytea), 4326))
>>> qs
<QuerySet [<WorldBorder: United States>]>
>>> sm = WorldBorder.objects.get(name='San Marino')
>>> sm.mpoly
<MultiPolygon object at 0x29dd54e8790>
>>> sm.mpoly.wkt
'MULTIPOLYGON (((12.415798 43.957954, 12.450554 43.979721, 12.453888 43.981667, 12.4625 43.984718, 12.471666 43.986938, 12.492777 43.989166, 12.505554 43.988609, 12.509998 43.986938, 12.510277 43.982773, 12.511665 43.943329, 12.510555 43.939163, 12.496387 43.923332, 12.494999 43.914719, 12.487778 43.90583, 12.474443 43.897217, 12.464722 43.895554, 12.459166 43.896111, 12.416388 43.904716, 12.412222 43.906105, 12.407822 43.913658, 12.403889 43.926666, 12.404999 43.948326, 12.408888 43.954994, 12.415798 43.957954)))'
>>> sm.mpoly.wkb
<memory at 0x0000029DD54A51C8>
>>> sm.mpoly.geojson
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], [ 12.453888, 43.981667 ], [ 12.4625, 43.984718 ], [ 12.471666, 43.986938 ], [ 12.492777, 43.989166 ], [ 12.505554, 43.988609 ], [ 12.509998, 43.986938 ], [ 12.510277, 43.982773 ], [ 12.511665, 43.943329 ], [ 12.510555, 43.939163 ], [ 12.496387, 43.923332 ], [ 12.494999, 43.914719 ], [ 12.487778, 43.90583 ], [ 12.474443, 43.897217 ], [ 12.464722, 43.895554 ], [ 12.459166, 43.896111 ], [ 12.416388, 43.904716 ], [ 12.412222, 43.906105 ], [ 12.407822, 43.913658 ], [ 12.403889, 43.926666 ], [ 12.404999, 43.948326 ], [ 12.408888, 43.954994 ], [ 12.415798, 43.957954 ] ] ] ] }'
>>> pnt = Point(12.4604, 43.9420)
>>> sm.mpoly.contains(pnt)
True
>>> pnt.contains(sm.mpoly)
False
>>> quit()
编辑world/admin.py
from django.contrib.gis import admin
from .models import WorldBorder
admin.site.register(WorldBorder, admin.OSMGeoAdmin)
编辑url.py
from django.contrib.gis import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
]
执行
(venv) D:\geodj\geodjango>python manage.py createsuperuser
Username (leave blank to use 'xxx'): xxx
Email address:
Error: Enter a valid email address.
Email address:
Password:
Password (again):
Superuser created successfully.
(venv) D:\geodj\geodjango>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
July 22, 2020 - 15:03:26
Django version 3.0.8, using settings 'geodjango.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
访问
http://localhost:8000/admin/
.
.
.
.
.
.
桃花仙人种桃树,又摘桃花换酒钱_