欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Windows 10 下 GEO Django 安装配置

程序员文章站 2022-04-01 20:41:30
...

1. 说明

1.1 所需软件

  1. Python 和 Django

  2. 空间数据库

    PostgreSQL/MySQL/Oracle/SQLite

  3. 地理相关库

数据库 库依赖
PostgreSQL GEOS, GDAL, PROJ.4, PostGIS
MySQL GEOS, GDAL
Oracle GEOS, GDAL
SQLite GEOS, GDAL, PROJ.4, SpatiaLite

1.2 实验环境

软件 版本
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

2. 安装过程

2.1 Python 和 Django

2.2 PostGIS

先安装PostgreSQL,安装完成后,提示运行Stack Builder.通过该工具安装PostGIS.

若Stack Builder扩展插件下载和安装失败,下载postgis-bundle-pg12x64-setup-3.0.1-3.exe手动完成.

2.3 psycopg2

psycopg2是python模块提供的Python和PostgreSQL数据库之间的接口,执行

pip install psycopg2

2.4 PROJ.4,GDAL和GEOS

OSGeo4W安装程序帮助安装GeoDjango所需的PROJ.4,GDAL和GEOS库.

  1. 下载OSGeo4W安装程序并运行
  2. 选择Express Web GIS安装,然后单击下一步
  3. selectpackages列表中确保选择了GDAL,单击“下一步”后
  4. 软件包将自动下载并安装,然后您可以退出安装程序.

2.5 配置环境变量

OSGEO4W_ROOTPYTHON_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%"

3. 测试GeoDjango

3.1 准备

  1. 创建项目和虚拟环境目录
D:\>cd geodj
D:\geodj>mkdir venv
  1. 创建虚拟环境
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
  1. **虚拟环境
D:\geodj>.\venv\scripts\activate
  1. 进入虚拟环境,装 Django
(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

3.2 创建新项目

  1. 创建项目,新建应用
(venv) D:\geodj>django-admin startproject geodjango

(venv) D:\geodj>cd geodjango

(venv) D:\geodj\geodjango>python manage.py startapp world
  1. 配置项目数据库和应用
# 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',   # 添加
]

3.2 查看地理数据

  1. 下载示例shp,命令行不成功就手动下载并解压到下目录,然后返回项目目录
(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 ..\..\
  1. 查看shp信息
(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)

3.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
  1. 数据迁移,可能出错误见最后
(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

3.4 GDAL接口读Shapefile数据

  1. 打开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)
  1. 打开Shapefile,导入表
>>> 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)
  1. 查看数据
>>> 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
* 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))

3.5 导入数据

  1. 创建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)
  1. 执行导入
(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: *
(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',
}
  1. 空间查询
(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()
  1. Django地图显示数据

编辑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/

.
.
.
.
.
.


桃花仙人种桃树,又摘桃花换酒钱_