Tutoriel GeoDjango¶
Introduction¶
GeoDjango est un module contribuĂ© de Django qui le transforme en un systĂšme gĂ©ographique web de grande envergure. Lâobjectif de GeoDjango est de faciliter le plus possible la crĂ©ation dâapplications web gĂ©ographiques telles que des services basĂ©s sur la gĂ©olocalisation. Ses fonctionnalitĂ©s comprennent :
- Des champs de modÚle Django pour les objets géométriques OGC rz les données matricielles.
- Des extensions de lâORM de Django pour les requĂȘtes et les manipulations des donnĂ©es spatiales.
- Des interfaces Python faiblement liées et de haut niveau pour les opérations géométriques SIG et matricielles et la manipulation de données dans divers formats.
- LâĂ©dition de champs gĂ©omĂ©triques dans lâinterface dâadministration.
Ce tutoriel part du principe que Django vous est familier ; si donc vous débutez avec Django, commencez par lire le tutoriel normal pour vous familiariser avec Django.
Note
GeoDjango requiert des dĂ©pendances supplĂ©mentaires par rapport Ă Django, consultez la documentation dâinstallation pour plus de dĂ©tails.
Ce tutoriel va vous guider dans les crĂ©ation dâune application web gĂ©ographique pour visualiser les frontiĂšres mondiales. [1] Une partie du code de ce tutoriel est empruntĂ© ou sâinspire du projet des applications de base GeoDjango. [2]
Note
Suivez dans lâordre les sections de ce tutoriel afin dâobtenir des instructions pas Ă pas.
Mise en route¶
CrĂ©ation dâune base de donnĂ©es spatiale¶
En rĂšgle gĂ©nĂ©rale, aucune configuration spĂ©ciale nâest requise, ce qui fait que vous pouvez crĂ©er une base de donnĂ©es comme pour nâimporte quel autre projet. Nous fournissons quelques astuces pour des bases de donnĂ©es prĂ©cises :
CrĂ©ation dâun nouveau projet¶
Utilisez le script standard django-admin
pour créer un projet nommé geodjango
:
$ django-admin startproject geodjango
...\> django-admin startproject geodjango
Ceci va initialiser un nouveau projet. Créez maintenant une application Django world
Ă lâintĂ©rieur du projet geodjango
:
$ cd geodjango
$ python manage.py startapp world
...\> cd geodjango
...\> py manage.py startapp world
Configuration de settings.py
¶
Les réglages du projet geodjango
sont dans le fichier geodjango/settings.py
. Modifiez les rĂ©glages de la connexion de base de donnĂ©es pour quâils correspondent Ă votre configuration :
DATABASES = {
"default": {
"ENGINE": "django.contrib.gis.db.backends.postgis",
"NAME": "geodjango",
"USER": "geo",
},
}
De plus, modifiez le réglage INSTALLED_APPS
pour quâil contienne django.contrib.admin
, django.contrib.gis
et world
(lâapplication que vous venez de crĂ©er) :
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.gis",
"world",
]
Données géographiques¶
FrontiÚres mondiales¶
Les données des frontiÚres mondiales sont disponibles dans ce fichier zip. Créez un répertoire data
dans lâapplication world
, téléchargez les données des frontiÚres mondiales et décompressez le fichier. Sur les plates-formes GNU/Linux, utilisez les commandes suivantes :
$ mkdir world/data
$ cd world/data
$ wget https://web.archive.org/web/20231220150759/https://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
$ unzip TM_WORLD_BORDERS-0.3.zip
$ cd ../..
...\> mkdir world\data
...\> cd world\data
...\> wget https://web.archive.org/web/20231220150759/https://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
...\> unzip TM_WORLD_BORDERS-0.3.zip
...\> cd ..\..
Le fichier ZIP des frontiĂšres mondiales contient un ensemble de fichiers de donnĂ©es formant ensemble ce quâon appelle un Shapefile ESRI, lâun des formats de donnĂ©es gĂ©ospatiales les plus utilisĂ©s. AprĂšs dĂ©compression, le jeu de donnĂ©es des frontiĂšres mondiales contient des fichiers avec les extensions suivantes :
.shp
: contient les données vectorielles des objets géométriques des frontiÚres mondiales..shx
: fichier dâindex spatial des objets gĂ©omĂ©triques stockĂ©s dans les fichiers.dbf
: fichier de base de donnĂ©es contenant les donnĂ©es dâattributs non gĂ©omĂ©triques (par ex. des champs de nombres entiers ou de texte)..prj
: contient les informations de référence spatiale pour les données géographiques stockées dans le shapefile.
Utilisation de ogrinfo
pour examiner les données spatiales¶
Lâutilitaire GDAL ogrinfo
permet dâexaminer les mĂ©tadonnĂ©es des shapefiles ou dâautres sources de donnĂ©es vectorielles :
$ 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)
...\> 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)
ogrinfo
nous indique que le shapefile possĂšde une couche et que celle-ci contient des donnĂ©es de type polygone. Pour en savoir plus, nous indiquons le nom de la couche et nous utilisons lâoption -so
pour nâafficher que le rĂ©sumĂ© des informations importantes :
$ 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
Geometry: Polygon
Feature Count: 246
Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)
Layer SRS WKT:
GEOGCS["GCS_WGS_1984",
DATUM["WGS_1984",
SPHEROID["WGS_1984",6378137.0,298.257223563]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]]
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: Integer (10.0)
REGION: Integer (3.0)
SUBREGION: Integer (3.0)
LON: Real (8.3)
LAT: Real (7.3)
...\> 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
Geometry: Polygon
Feature Count: 246
Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)
Layer SRS WKT:
GEOGCS["GCS_WGS_1984",
DATUM["WGS_1984",
SPHEROID["WGS_1984",6378137.0,298.257223563]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]]
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: Integer (10.0)
REGION: Integer (3.0)
SUBREGION: Integer (3.0)
LON: Real (8.3)
LAT: Real (7.3)
Ce rĂ©sumĂ© dâinformations dĂ©taillĂ© nous indique le nombre dâobjets dans la couche (246), les limites gĂ©ographiques des donnĂ©es, le systĂšme de rĂ©fĂ©rence spatial (« SRS WKT ») ainsi que le type dâinformation de chaque champ dâattribut. Par exemple, FIPS: String (2.0)
indique que la longueur maximale du champ textuel FIPS
est de 2 caractĂšres. De mĂȘme, LON: Real (8.3)
correspond Ă un champ nombre en virgule flottante contenant un maximum de 8 chiffres avant la virgule et 3 aprĂšs.
ModÚles géographiques¶
DĂ©finition dâun modĂšle gĂ©ographique¶
AprĂšs avoir examinĂ© le jeu de donnĂ©es Ă lâaide de ogrinfo
, créez un modÚle GeoDjango pour représenter ces données :
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
Notez que le module models
est importé à partir de django.contrib.gis.db
.
Le systĂšme de rĂ©fĂ©rence spatial par dĂ©faut des champs gĂ©omĂ©triques est WGS84 (ce qui implique une valeur de SRID de 4326) ; en dâautres termes, les coordonnĂ©es du champ sont des couples longitude/latitude en degrĂ©s. Pour utiliser un systĂšme de coordonnĂ©es diffĂ©rent, dĂ©finissez le SRID du champ gĂ©omĂ©trique avec le paramĂštre srid
. Utilisez un nombre entier représentant le code EPSG du systÚme de coordonnées.
Exécutez migrate
¶
AprĂšs avoir dĂ©fini le modĂšle, vous devez le synchroniser avec la base de donnĂ©es. CrĂ©ez tout dâabord une migration de base de donnĂ©es :
$ python manage.py makemigrations
Migrations for 'world':
world/migrations/0001_initial.py:
- Create model WorldBorder
...\> py manage.py makemigrations
Migrations for 'world':
world/migrations/0001_initial.py:
- Create model WorldBorder
Examinons le code SQL qui générera la table du modÚle WorldBorder
:
$ python manage.py sqlmigrate world 0001
...\> py manage.py sqlmigrate world 0001
Cette commande devrait produire le résultat suivant :
BEGIN;
--
-- Create model WorldBorder
--
CREATE TABLE "world_worldborder" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(50) NOT NULL,
"area" integer NOT NULL,
"pop2005" integer NOT NULL,
"fips" varchar(2) NOT 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;
Si cela vous semble correct, exécutez migrate
pour créer la table dans la base de données :
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, world
Running migrations:
...
Applying world.0001_initial... OK
...\> py manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, world
Running migrations:
...
Applying world.0001_initial... OK
Importation de données spatiales¶
Cette section prĂ©sente la maniĂšre dâimporter le fichier des frontiĂšres mondiales dans une base de donnĂ©es via les modĂšles GeoDjango en utilisant lâUtilitaire dâimportation de donnĂ©es LayerMapping.
Il existe plusieurs façons dâimporter des donnĂ©es dans une base de donnĂ©es spatiale ; en plus des outils inclus avec GeoDjango, il est aussi possible dâutiliser :
- ogr2ogr: un utilitaire en ligne de commande inclus dans GDAL et qui peut importer de nombreux formats de données vectorielles dans des bases de données PostGIS, MySQL et Oracle.
- shp2pgsql: cet utilitaire inclus dans PostGIS importe des shapefiles ESRI dans PostGIS.
Interface GDAL¶
Vous avez précédemment utilisé ogrinfo
pour examiner le contenu du fichier des frontiÚres mondiales. GeoDjango contient également une interface Python vers la puissante bibliothÚque OGR de GDAL qui est capable de traiter toutes les sources de données vectorielles prises en charge par OGR.
PremiĂšrement, lancez le shell Django :
$ python manage.py shell
...\> py manage.py shell
Si vous avez téléchargé les données FrontiÚres mondiales précédemment dans ce tutoriel, vous pouvez déterminer son chemin en utilisant pathlib.Path
de Python :
>>> from pathlib import Path
>>> import world
>>> world_shp = Path(world.__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"
Ouvrez maintenant le fichier shapefile des frontiĂšres mondiales en utilisant lâinterface DataSource
de GeoDjango :
>>> from django.contrib.gis.gdal import DataSource
>>> ds = DataSource(world_shp)
>>> print(ds)
/ ... /geodjango/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)
Les objets des sources de donnĂ©es peuvent possĂ©der plusieurs couches de contenu gĂ©ospatial ; cependant, les fichiers shapefile ne peuvent contenir quâune seule couche :
>>> print(len(ds))
1
>>> lyr = ds[0]
>>> print(lyr)
TM_WORLD_BORDERS-0.3
Vous pouvez voir le type gĂ©omĂ©trique de la couche ainsi que le nombre dâobjets quâelle contient :
>>> print(lyr.geom_type)
Polygon
>>> print(len(lyr))
246
Note
Malheureusement, le format de donnĂ©es shapefile ne permet pas de plus grande prĂ©cision concernant le type gĂ©omĂ©trique. Ce fichier shapefile, comme beaucoup dâautres, contient en rĂ©alitĂ© des objets gĂ©omĂ©triques MultiPolygon
, et non pas des Polygon
. Il est important dâutiliser un type de champ plus gĂ©nĂ©ral dans les modĂšles : un champ MultiPolygonField
de GeoDjango acceptera un objet Polygon
, mais un champ PolygonField
nâacceptera pas un objet gĂ©omĂ©trique de type MultiPolygon
. Câest pourquoi le modĂšle WorldBorder
défini ci-dessus utilise un champ MultiPolygonField
.
Il est aussi possible quâun systĂšme de rĂ©fĂ©rence spatial soit associĂ© Ă lâobjet Layer
. Si câest le cas, lâattribut srs
renvoie un objet SpatialReference
:
>>> 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.proj # PROJ representation
'+proj=longlat +datum=WGS84 +no_defs'
Ce fichier shapefile utilise le systĂšme de rĂ©fĂ©rence spatial bien connu WGS84 ; en dâautres termes, les donnĂ©es sont reprĂ©sentĂ©es par des couples longitude/latitude en degrĂ©s.
De plus, les fichiers shapefile peuvent aussi contenir des champs dâattributs comportant des donnĂ©es supplĂ©mentaires. Voici ces champs pour la couche World Borders
:
>>> print(lyr.fields)
['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT']
Le code suivant permet dâexaminer le type OGR (par ex. nombre entier ou chaĂźne de caractĂšres) associĂ© Ă chaque champ :
>>> [fld.__name__ for fld in lyr.field_types]
['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger64', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal']
Il est possible de parcourir chaque objet de la couche et dâextraire des informations Ă la fois de la gĂ©omĂ©trie des objets (accessible par lâattribut geom
) et des champs dâattribut des objets (dont les valeurs sont accessibles par la mĂ©thode get()
) :
>>> for feat in lyr:
... print(feat.get("NAME"), feat.geom.num_points)
...
Guernsey 18
Jersey 26
South Georgia South Sandwich Islands 338
Taiwan 363
Les objets Layer
peuvent ĂȘtre segmentĂ©s :
>>> lyr[0:2]
[<django.contrib.gis.gdal.feature.Feature object at 0x2f47690>, <django.contrib.gis.gdal.feature.Feature object at 0x2f47650>]
Et des objets individuels peuvent ĂȘtre rĂ©cupĂ©rĂ©s par leur identifiant dâobjet :
>>> feat = lyr[234]
>>> print(feat.get("NAME"))
San Marino
Les objets gĂ©omĂ©triques des frontiĂšres peuvent ĂȘtre exportĂ©s en tant que WKT ou GeoJSON :
>>> geom = feat.geom
>>> print(geom.wkt)
POLYGON ((12.415798 43.957954,12.450554 ...
>>> print(geom.json)
{ "type": "Polygon", "coordinates": [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...
Cartographie des couches (LayerMapping
)¶
Pour importer les données, utilisez un objet LayerMapping
dans un script Python. Créez un fichier nommé load.py
dans lâapplication world
et insérez-y le code suivant :
from pathlib import Path
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 = Path(__file__).resolve().parent / "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)
Quelques notes au sujet du procédé :
- Chaque clé du dictionnaire
world_mapping
correspond Ă un champ du modĂšleWorldBorder
. La valeur est le nom du champ du shapefile duquel les données seront chargées. - La clé
mpoly
du champ géométrique estMULTIPOLYGON
, le type gĂ©omĂ©trique que GeoDjango utilisera pour importer le champ. MĂȘme de simples polygones dans le fichier shapefile seront automatiquement convertis en collections avant leur insertion dans la base de donnĂ©es. - Le chemin vers le fichier shapefile nâest pas absolu ; en dâautres termes, si vous dĂ©placez lâapplication
world
(contenant le sous-répertoiredata
) vers un autre emplacement, le script fonctionne toujours. - Le paramĂštre
transform
est dĂ©fini ĂFalse
car les donnĂ©es du fichier shapefile ne doivent pas ĂȘtre converties, elles sont dĂ©jĂ au format WGS84 (SRID=4326).
AprÚs cela, appelez le shell Django à partir du répertoire de projet geodjango
:
$ python manage.py shell
...\> py manage.py shell
Puis, importez le module load
, appelez la routine run
et observez LayerMapping
effectuant tout le travail :
>>> from world import load
>>> load.run()
Utilisation de ogrinspect
¶
Maintenant que vous avez vu comment dĂ©finir des modĂšles gĂ©ographiques et importer des donnĂ©es avec lâUtilitaire dâimportation de donnĂ©es LayerMapping, il est possible dâautomatiser davantage ce processus Ă lâaide de la commande de gestion ogrinspect
. La commande ogrinspect
inspecte une source de donnĂ©es vectorielle prise en charge par GDAL (par ex. un shapefile) et gĂ©nĂšre automatiquement une dĂ©finition de modĂšle ainsi quâun dictionnaire LayerMapping
.
Lâutilisation gĂ©nĂ©rale de la commande correspond Ă ceci :
$ python manage.py ogrinspect [options] <data_source> <model_name> [options]
...\> py manage.py ogrinspect [options] <data_source> <model_name> [options]
data_source
est le chemin vers la source de données prise en charge par GDAL et model_name
est le nom Ă utiliser pour le modĂšle. Les options en ligne de commande peuvent ĂȘtre utilisĂ©es pour dĂ©finir plus finement la maniĂšre dont le modĂšle doit ĂȘtre gĂ©nĂ©rĂ©.
Par exemple, la commande suivante reproduit presque le modĂšle WorldBorder
et le dictionnaire de correspondance créés ci-dessus, de façon automatique :
$ python manage.py ogrinspect world/data/TM_WORLD_BORDERS-0.3.shp WorldBorder \
--srid=4326 --mapping --multi
...\> py manage.py ogrinspect world\data\TM_WORLD_BORDERS-0.3.shp WorldBorder \
--srid=4326 --mapping --multi
Quelques notes sur les options de ligne de commande indiquées ci-dessus :
- Lâoption
--srid=4326
dĂ©finit le SRID du champ gĂ©ographique. - Lâoption
--mapping
indique Ăogrinspect
de gĂ©nĂ©rer aussi un dictionnaire de correspondance Ă lâusage deLayerMapping
. - Lâoption
--multi
est indiquée pour que le champ géographique utiliseMultiPolygonField
au lieu dâun simplePolygonField
.
La commande produit le rĂ©sultat suivant, qui peut ĂȘtre directement copiĂ© dans un fichier models.py
dâune application GeoDjango :
# 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.IntegerField()
region = models.IntegerField()
subregion = models.IntegerField()
lon = models.FloatField()
lat = models.FloatField()
geom = models.MultiPolygonField(srid=4326)
# Auto-generated `LayerMapping` dictionary for WorldBorder model
worldborders_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",
}
RequĂȘtes spatiales¶
Recherches spatiales¶
GeoDjango ajoute des recherches spatiales Ă lâORM de Django. Par exemple, vous pouvez chercher le pays de la table WorldBorder
qui contient un point particulier. Commencez par lancer un shell de commande :
$ python manage.py shell
...\> py manage.py shell
DĂ©finissez maintenant un point dâintĂ©rĂȘt [3]:
>>> pnt_wkt = "POINT(-95.3385 29.7245)"
La chaĂźne pnt_wkt
représente le point situé à la longitude -95.3385 degrés et la latitude 29.7245 degrés. La syntaxe géométrique est dans un format connu sous le nom de Well Known Text (WKT), un standard émis par le consortium Open Geospatial (OGC). [4] Importez le modÚle WorldBorder
et lancez une recherche contains
avec pnt_wkt
en paramĂštre :
>>> from world.models import WorldBorder
>>> WorldBorder.objects.filter(mpoly__contains=pnt_wkt)
<QuerySet [<WorldBorder: United States>]>
Vous venez dâobtenir un QuerySet
contenant un seul modĂšle : la frontiĂšre des Ătats-Unis (exactement ce que lâon espĂ©rait).
De la mĂȘme façon, vous pouvez aussi utiliser un objet gĂ©omĂ©trique GEOS. Ici, vous pouvez combiner une requĂȘte spatiale intersects
avec la méthode get
pour obtenir la seule instance de Saint-Marin au lieu dâun queryset :
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(12.4604, 43.9420)
>>> WorldBorder.objects.get(mpoly__intersects=pnt)
<WorldBorder: San Marino>
Les recherches contains
et intersects
ne sont quâun sous-ensemble des recherches possibles, consultez la documentation API de base de donnĂ©es GeoDjango pour plus de dĂ©tails.
Transformations spatiales automatiques¶
Lors de lâexĂ©cution de requĂȘtes spatiales, GeoDjango transforme automatiquement les objets gĂ©omĂ©triques sâils sont dans un systĂšme de coordonnĂ©es diffĂ©rent. Dans lâexemple suivant, les coordonnĂ©es seront exprimĂ©es en SRID EPSG 32140, un systĂšme de coordonnĂ©es purement spĂ©cifique au Texas du Sud et en mĂštres, pas en degrĂ©s :
>>> from django.contrib.gis.geos import GEOSGeometry, Point
>>> pnt = Point(954158.1, 4215137.1, srid=32140)
Notez que pnt
peut aussi ĂȘtre construit avec EWKT, une forme « Ă©tendue » de WKT qui contient le SRID :
>>> pnt = GEOSGeometry("SRID=32140;POINT(954158.1 4215137.1)")
LâORM de GeoDjango adapte automatiquement les valeurs gĂ©omĂ©triques dans le code de transformation SQL adĂ©quat, permettant au dĂ©veloppeur de travailler Ă un haut niveau dâabstraction :
>>> qs = WorldBorder.objects.filter(mpoly__intersects=pnt)
>>> print(qs.query) # Generating the SQL
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" FROM "world_worldborder"
WHERE ST_Intersects("world_worldborder"."mpoly", ST_Transform(%s, 4326))
>>> qs # printing evaluates the queryset
<QuerySet [<WorldBorder: United States>]>
RequĂȘtes brutes
Lors de lâutilisation de requĂȘtes brutes, vous devez entourer vos champs gĂ©omĂ©triques afin que la valeur du champ soit reconnue par GEOS :
>>> from django.db import connection
>>> # or if you're querying a non-default database:
>>> from django.db import connections
>>> connection = connections["your_gis_db_alias"]
>>> City.objects.raw(
... "SELECT id, name, %s as point from myapp_city" % (connection.ops.select % "point")
... )
Les requĂȘtes brutes ne devraient ĂȘtre utilisĂ©es que lorsque lâon sait exactement ce que lâon fait.
Objets géométriques différés¶
GeoDjango charge les objets géométriques dans une représentation textuelle standardisée. Lors du premier accÚs au champ géométrique, GeoDjango crée un objet GEOSGeometry
exposant des fonctionnalités puissantes comme des propriétés de sérialisation pour des formats géospatiaux populaires :
>>> sm = WorldBorder.objects.get(name="San Marino")
>>> sm.mpoly
<MultiPolygon object at 0x24c6798>
>>> sm.mpoly.wkt # WKT
MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ...
>>> sm.mpoly.wkb # WKB (as Python binary buffer)
<read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40>
>>> sm.mpoly.geojson # GeoJSON
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...
Cela comprend aussi lâaccĂšs Ă toutes les opĂ©rations gĂ©omĂ©triques avancĂ©es fournies par la bibliothĂšque GEOS :
>>> pnt = Point(12.4604, 43.9420)
>>> sm.mpoly.contains(pnt)
True
>>> pnt.contains(sm.mpoly)
False
Annotations géographiques¶
GeoDjango propose Ă©galement un ensemble dâannotations gĂ©ographiques pour calculer les distances et diverses autres opĂ©rations (intersection, diffĂ©rence, etc.). Voir la documentation Fonctions de base de donnĂ©es gĂ©ographiques.
Placement des données sur une carte¶
Interface dâadministration gĂ©ographique¶
Lâapplication dâadministration de Django prend en charge lâĂ©dition des champs gĂ©omĂ©triques.
Généralités¶
Lâadministration de Django permet aux utilisateurs de crĂ©er et modifier des objets gĂ©omĂ©triques sur une carte active JavaScript (basĂ©e sur OpenLayers).
Mettons-nous au travail. Créez un fichier nommé admin.py
dans lâapplication world
et placez-y le code suivant :
from django.contrib.gis import admin
from .models import WorldBorder
admin.site.register(WorldBorder, admin.ModelAdmin)
Puis, modifiez urls.py
dans le dossier dâapplication geodjango
comme ceci :
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
]
Créez un utilisateur administrateur :
$ python manage.py createsuperuser
...\> py manage.py createsuperuser
Puis, démarrez le serveur de développement Django :
$ python manage.py runserver
...\> py manage.py runserver
Pour terminer, allez Ă lâadresse http://localhost:8000/admin/
et connectez-vous avec lâutilisateur que vous venez de crĂ©er. Parcourez lâun des objets WorldBorder
et constatez que les frontiĂšres peuvent ĂȘtre modifiĂ©es en cliquant sur un polygone et en faisant glisser ses arĂȘtes Ă la position souhaitĂ©e.
GISModelAdmin
¶
Avec GISModelAdmin
, GeoDjango utilise une couche OpenStreetMap dans lâinterface dâadministration. Cela donne plus de contexte (y compris les dĂ©tails des rues et des voies de communication) que lâinterface disponible avec ModelAdmin
(qui utilise le jeu de données WMS Vector Map Level 0 hébergé sur OSGeo).
Les fichiers de projections PROJ doivent ĂȘtre installĂ©s (voir les instructions dâinstallation de PROJ pour plus de dĂ©tails).
Si cette exigence est satisfaite, vous pouvez utiliser la classe GISModelAdmin
dans le fichier admin.py
:
admin.site.register(WorldBorder, admin.GISModelAdmin)
Notes de bas de page
[1] | Un merci particulier à BjÞrn Sandvik de mastermaps.net <https://mastermaps.net/>`_ pour la mise à disposition et la maintenance de ce jeu de données. |
[2] | Les applications GeoDjango de base ont été écrites par Dane Springmeyer, Josh Livni et Christopher Schmidt. |
[3] | Ce point correspond Ă University of Houston Law Center. |
[4] | Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification For SQL `_. |