# Django 6.0.7 documentation

# GeoDjango handledning

## Introduktion

GeoDjango är en medföljande Contrib-modul för Django som förvandlar den till ett geografiskt webbramverk i världsklass. GeoDjango strävar efter att göra det så enkelt som möjligt att skapa geografiska webbapplikationer, t.ex. platsbaserade tjänster. Dess funktioner inkluderar:

- Django-modellfält för OGC-geometrier och rasterdata.

- Tillägg till Djangos ORM för frågor och manipulering av rumsliga data.

- Löst kopplade Python-gränssnitt på hög nivå för GIS-geometri och rasteroperationer samt datahantering i olika format.

- Redigering av geometriska fält från administratören.

Denna handledning förutsätter att du känner till Django; om du är helt ny på Django, läs därför igenom vanlig handledning för att bekanta dig med Django först.

Observera

GeoDjango has additional requirements beyond what Django requires – please consult the installation documentation for more details.

Denna handledning kommer att vägleda dig genom skapandet av en geografisk webbapplikation för visning av världsgränserna. [1] En del av koden som används i denna handledning är hämtad från och/eller inspirerad av projektet GeoDjango basic apps. [2]

Observera

Gå igenom handledningsavsnitten i tur och ordning för att få steg-för-steg-instruktioner.

## Uppsättning

### Skapa en rumslig databas

Vanligtvis krävs ingen speciell installation, så du kan skapa en databas som du skulle göra för vilket annat projekt som helst. Vi ger några tips för utvalda databaser:

- Installera PostGIS

- Installera SpatiaLite

### Skapa ett nytt projekt

Använd standardskriptet `django-admin` för att skapa ett projekt som heter `geodjango`:

/ 

    $ django-admin startproject geodjango

    ...\> django-admin startproject geodjango

Detta kommer att initiera ett nytt projekt. Nu skapar du en Django-applikation `world` inom `geodjango`-projektet:

/ 

    $ cd geodjango
    $ python manage.py startapp world

    ...\> cd geodjango
    ...\> py manage.py startapp world

### Konfigurera `settings.py`

Projektinställningarna för `geodjango` lagras i filen `geodjango/settings.py`. Redigera databasanslutningsinställningarna så att de matchar din installation:

    DATABASES = {
        "default": {
            "ENGINE": "django.contrib.gis.db.backends.postgis",
            "NAME": "geodjango",
            "USER": "geo",
        },
    }

Ändra dessutom inställningen `INSTALLED_APPS` så att den inkluderar `django.contrib.admin`, `django.contrib.gis` och `world` (din nyskapade applikation):

    INSTALLED_APPS = [
        "django.contrib.admin",
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.messages",
        "django.contrib.staticfiles",
        "django.contrib.gis",
        "world",
    ]

## Geografiska data

### Världsgränser

The world borders data is available in this zip file. Create a `data` directory in the `world` application, download the world borders data, and unzip. On GNU/Linux platforms, use the following commands:

/ 

    $ 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 ..\..

The world borders ZIP file contains a set of data files collectively known as an ESRI Shapefile, one of the most popular geospatial data formats. When unzipped, the world borders dataset includes files with the following extensions:

- `.shp`: Innehåller vektordata för världsgränsgeometrierna.

- `.shx`: Rumslig indexfil för geometrier lagrade i `.shp`.

- `.dbf`: Databasfil för icke-geometriska attributdata (t.ex. heltals- och teckenfält).

- `.prj`: Innehåller den rumsliga referensinformationen för de geografiska data som lagras i shapefilen.

### Använd `ogrinfo` för att undersöka rumsliga data

GDAL:s verktyg `ogrinfo` gör det möjligt att undersöka metadata för shapefiler eller andra vektordatakällor:

/ 

    $ 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` tells us that the shapefile has one layer, and that this layer contains polygon data. To find out more, we’ll specify the layer name and use the `-so` option to get only the important summary information:

/ 

    $ 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)

    ...\> 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)

This detailed summary information tells us the number of features in the layer (246), the geographic bounds of the data, the spatial reference system (”SRS WKT”), as well as type information for each attribute field. For example, `FIPS: String (2.0)` indicates that the `FIPS` character field has a maximum length of 2. Similarly, `LON: Real (8.3)` is a floating-point field that holds a maximum of 8 digits up to three decimal places.

## Geografiska modeller

### Definiera en geografisk modell

Nu när du har undersökt din dataset med hjälp av `ogrinfo`, skapa en GeoDjango modell för att representera dessa data:

    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

Observera att modulen `models` importeras från `django.contrib.gis.db`.

The default spatial reference system for geometry fields is WGS84 (meaning the SRID is 4326) – in other words, the field coordinates are in longitude, latitude pairs in units of degrees. To use a different coordinate system, set the SRID of the geometry field with the `srid` argument. Use an integer representing the coordinate system’s EPSG code.

### Kör `migrate`

När du har definierat din modell måste du synkronisera den med databasen. Först skapar du en databasmigrering:

/ 

    $ 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

Låt oss titta på den SQL som kommer att generera tabellen för modellen `WorldBorder`:

/ 

    $ python manage.py sqlmigrate world 0001

    ...\> py manage.py sqlmigrate world 0001

Detta kommando bör ge följande resultat:

    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;

Om detta ser korrekt ut, kör `migrate` för att skapa denna tabell i databasen:

/ 

    $ 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

## Importera rumsliga data

This section will show you how to import the world borders shapefile into the database via GeoDjango models using the LayerMapping verktyg för dataimport.

Det finns många olika sätt att importera data till en rumslig databas - förutom de verktyg som ingår i GeoDjango kan du också använda följande:

- ogr2ogr: Ett kommandoradsverktyg som ingår i GDAL och som kan importera många vektordataformat till PostGIS-, MySQL- och Oracle-databaser.

- shp2pgsql: Detta verktyg som ingår i PostGIS importerar ESRI shapefiler till PostGIS.

### GDAL-gränssnitt

Earlier, you used `ogrinfo` to examine the contents of the world borders shapefile. GeoDjango also includes a Pythonic interface to GDAL’s powerful OGR library that can work with all the vector data sources that OGR supports.

Först anropar du Django-skalet:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

Om du hämtade data från Världsgränser tidigare i handledningen kan du bestämma dess sökväg med hjälp av Pythons `pathlib.Path`:

    >>> from pathlib import Path
    >>> import world
    >>> world_shp = Path(world.__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"

Öppna nu shapefilen med världsgränser med hjälp av GeoDjangos `DataSource`-gränssnitt:

    >>> from django.contrib.gis.gdal import DataSource
    >>> ds = DataSource(world_shp)
    >>> print(ds)
    / ... /geodjango/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)

Datakällobjekt kan ha olika lager av geospatiala funktioner, men shapefiler får bara ha ett lager:

    >>> print(len(ds))
    1
    >>> lyr = ds[0]
    >>> print(lyr)
    TM_WORLD_BORDERS-0.3

Du kan se skiktets geometrityp och hur många funktioner det innehåller:

    >>> print(lyr.geom_type)
    Polygon
    >>> print(len(lyr))
    246

Observera

Unfortunately, the shapefile data format does not allow for greater specificity with regards to geometry types. This shapefile, like many others, actually includes `MultiPolygon` geometries, not Polygons. It’s important to use a more general field type in models: a GeoDjango `MultiPolygonField` will accept a `Polygon` geometry, but a `PolygonField` will not accept a `MultiPolygon` type geometry. This is why the `WorldBorder` model defined above uses a `MultiPolygonField`.

The `Layer` may also have a spatial reference system associated with it. If it does, the `srs` attribute will return a `SpatialReference` object:

    >>> 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'

Denna shapefil är i det populära rumsliga referenssystemet WGS84 - med andra ord använder data par av longitud, latitud i enheter av grader.

In addition, shapefiles also support attribute fields that may contain additional data. Here are the fields on the World Borders layer:

    >>> print(lyr.fields)
    ['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT']

Med följande kod kan du undersöka de OGR-typer (t.ex. heltal eller sträng) som är associerade med vart och ett av fälten:

    >>> [fld.__name__ for fld in lyr.field_types]
    ['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger64', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal']

Du kan iterera över varje objekt i skiktet och extrahera information från både objektets geometri (som nås via attributet `geom`) och objektets attributfält (vars värden nås via metoden `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

`Layer`-objekt kan skivas:

    >>> lyr[0:2]
    [<django.contrib.gis.gdal.feature.Feature object at 0x2f47690>, <django.contrib.gis.gdal.feature.Feature object at 0x2f47650>]

Och enskilda funktioner kan hämtas med hjälp av deras funktions-ID:

    >>> feat = lyr[234]
    >>> print(feat.get("NAME"))
    San Marino

Gränsgeometrier kan exporteras som WKT och 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 ], ...

### `LayerMapping`

För att importera data använder du en `LayerMapping` i ett Python-skript. Skapa en fil som heter `load.py` i applikationen `world` med följande kod:

    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)

Några anteckningar om vad som händer:

- Each key in the `world_mapping` dictionary corresponds to a field in the `WorldBorder` model. The value is the name of the shapefile field that data will be loaded from.

- The key `mpoly` for the geometry field is `MULTIPOLYGON`, the geometry type GeoDjango will import the field as. Even simple polygons in the shapefile will automatically be converted into collections prior to insertion into the database.

- Sökvägen till shapefilen är inte absolut - med andra ord, om du flyttar programmet `world` (med underkatalogen `data`) till en annan plats kommer skriptet fortfarande att fungera.

- Nyckelordet `transform` är inställt på `False` eftersom data i shapefilen inte behöver konverteras - de finns redan i WGS84 (SRID=4326).

Därefter anropar du Django-skalet från projektkatalogen `geodjango`:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

Därefter importerar du modulen `load`, anropar rutinen `run` och ser `LayerMapping` göra jobbet:

    >>> from world import load
    >>> load.run()

### Prova `ogrinspect`

Now that you’ve seen how to define geographic models and import data with the LayerMapping verktyg för dataimport, it’s possible to further automate this process with use of the `ogrinspect` management command. The `ogrinspect` command introspects a GDAL-supported vector data source (e.g., a shapefile) and generates a model definition and `LayerMapping` dictionary automatically.

Den allmänna användningen av kommandot går till på följande sätt:

/ 

    $ python manage.py ogrinspect [options] <data_source> <model_name> [options]

    ...\> py manage.py ogrinspect [options] <data_source> <model_name> [options]

`data_source` is the path to the GDAL-supported data source and `model_name` is the name to use for the model. Command-line options may be used to further define how the model is generated.

Exempelvis kan följande kommando nästan automatiskt reproducera modellen `WorldBorder` och mappningsordlistan som skapats ovan:

/ 

    $ 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

Några kommentarer om de kommandoradsalternativ som anges ovan:

- Alternativet `--srid=4326` anger SRID för det geografiska fältet.

- Alternativet `--mapping` säger till `ogrinspect` att även generera en mappningsordbok för användning med `LayerMapping`.

- Alternativet `--multi` anges så att det geografiska fältet är en `MultiPolygonField` istället för bara en `PolygonField`.

Kommandot ger följande resultat, som kan kopieras direkt till `models.py` i en GeoDjango-applikation:

    # 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",
    }

## Rumsliga frågor

### Rumsliga uppslagningar

GeoDjango adds spatial lookups to the Django ORM. For example, you can find the country in the `WorldBorder` table that contains a particular point. First, fire up the management shell:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

Nu ska du definiera en intressepunkt [3]:

    >>> pnt_wkt = "POINT(-95.3385 29.7245)"

The `pnt_wkt` string represents the point at -95.3385 degrees longitude, 29.7245 degrees latitude. The geometry is in a format known as Well Known Text (WKT), a standard issued by the Open Geospatial Consortium (OGC). [4] Import the `WorldBorder` model, and perform a `contains` lookup using the `pnt_wkt` as the parameter:

    >>> from world.models import WorldBorder
    >>> WorldBorder.objects.filter(mpoly__contains=pnt_wkt)
    <QuerySet [<WorldBorder: United States>]>

Here, you retrieved a `QuerySet` with only one model instance: the border of the United States (exactly what you would expect).

Similarly, you may also use a GEOS geometry object. Here, you can combine the `intersects` spatial lookup with the `get` method to retrieve only the `WorldBorder` instance for San Marino instead of a queryset:

    >>> from django.contrib.gis.geos import Point
    >>> pnt = Point(12.4604, 43.9420)
    >>> WorldBorder.objects.get(mpoly__intersects=pnt)
    <WorldBorder: San Marino>

The `contains` and `intersects` lookups are just a subset of the available queries – the GeoDjango databas API documentation has more.

### Automatiska rumsliga omvandlingar

When doing spatial queries, GeoDjango automatically transforms geometries if they’re in a different coordinate system. In the following example, coordinates will be expressed in EPSG SRID 32140, a coordinate system specific to south Texas only and in units of meters, not degrees:

    >>> from django.contrib.gis.geos import GEOSGeometry, Point
    >>> pnt = Point(954158.1, 4215137.1, srid=32140)

Observera att `pnt` också kan konstrueras med EWKT, en ”utökad” form av WKT som inkluderar SRID:

    >>> pnt = GEOSGeometry("SRID=32140;POINT(954158.1 4215137.1)")

GeoDjangos ORM slår automatiskt in geometrivärden i transformations-SQL, vilket gör att utvecklaren kan arbeta på en högre abstraktionsnivå:

    >>> 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>]>

Råa förfrågningar

När du använder raw queries måste du omsluta dina geometrifält så att fältvärdet kan identifieras av 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")
    ... )

Du bör bara använda råa frågor när du vet exakt vad du gör.

### Lata geometrier

GeoDjango loads geometries in a standardized textual representation. When the geometry field is first accessed, GeoDjango creates a `GEOSGeometry` object, exposing powerful functionality, such as serialization properties for popular geospatial formats:

    >>> 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 ], ...

Detta inkluderar tillgång till alla avancerade geometriska operationer som tillhandahålls av GEOS-biblioteket:

    >>> pnt = Point(12.4604, 43.9420)
    >>> sm.mpoly.contains(pnt)
    True
    >>> pnt.contains(sm.mpoly)
    False

### Geografiska anteckningar

GeoDjango also offers a set of geographic annotations to compute distances and several other operations (intersection, difference, etc.). See the Geografiska databasfunktioner documentation.

## Placera dina data på kartan

### Geografisk administratör

Djangos admin-applikation stöder redigering av geometriska fält.

#### Grundläggande

Django-admin låter användare skapa och ändra geometrier på en JavaScript-karta (som drivs av OpenLayers).

Låt oss dyka rätt in. Skapa en fil som heter `admin.py` inuti applikationen `world` med följande kod:

    from django.contrib.gis import admin
    from .models import WorldBorder

    admin.site.register(WorldBorder, admin.ModelAdmin)

Därefter redigerar du din `urls.py` i applikationsmappen `geodjango` enligt följande:

    from django.contrib import admin
    from django.urls import include, path

    urlpatterns = [
        path("admin/", admin.site.urls),
    ]

Skapa en administratörsanvändare:

/ 

    $ python manage.py createsuperuser

    ...\> py manage.py createsuperuser

Starta sedan upp Django-utvecklingsservern:

/ 

    $ python manage.py runserver

    ...\> py manage.py runserver

Slutligen, bläddra till `http://localhost:8000/admin/` och logga in med den användare du just skapat. Bläddra till någon av `WorldBorder`-posterna - gränserna kan redigeras genom att klicka på en polygon och dra hörnen till önskad position.

#### `GISModelAdmin`

Med `GISModelAdmin` använder GeoDjango ett OpenStreetMap-lager i admin. Detta ger mer sammanhang (inklusive detaljer om gator och genomfartsleder) än vad som är tillgängligt med `ModelAdmin` (som använder WMS-datasetet Vector Map Level 0 som finns hos OSGeo).

PROJ datumskiftesfiler måste installeras (se PROJ installationsinstruktioner för mer information).

Om du uppfyller detta krav kan du använda alternativklassen `GISModelAdmin` i filen `admin.py`:

    admin.site.register(WorldBorder, admin.GISModelAdmin)

Fotnoter

[1]

Ett särskilt tack till Bjørn Sandvik på mastermaps.net för tillhandahållande och underhåll av detta dataset.

[2]

GeoDjango basic apps är skriven av Dane Springmeyer, Josh Livni och Christopher Schmidt.

[3]

Denna punkt är University of Houston Law Center.

[4]

Open Geospatial Consortium, Inc, OpenGIS Simple Feature Specification For SQL.