PostGIS Integration

Environment Setup

Docker Configuration

Below are the changes needed to set up the environment for PostGIS and GDAL.

Dockerfile Modifications

Add the necessary dependencies for GDAL:

# Install GDAL and related dependencies
RUN apt-get update && apt-get install -y binutils libproj-dev gdal-bin libgdal-dev

# Set environment variables for GDAL
ENV GDAL_LIBRARY_PATH=/usr/lib/libgdal.so
ENV GEOS_LIBRARY_PATH=/usr/lib/libgeos_c.so

docker-compose.yml Modifications

Replace the default database image with the official PostGIS image:

services:
  db:
    image: postgis/postgis:latest
    restart: always
    ports:
      - "5433:5432"
    env_file:
      - .env
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pgdata:

PostGIS Integration in Django

Step 1: Use PointField and PolygonField in Models and Serializers

Below is an example of how to define models in Django that include geospatial fields such as PointField and PolygonField.

Models

from django.contrib.gis.db import models

class Location(models.Model):
    name = models.CharField(max_length=100)
    position = models.PointField()  # Field to store a geospatial point

class Region(models.Model):
    name = models.CharField(max_length=100)
    area = models.PolygonField()  # Field to store a geospatial polygon

Serializers and forms

If you are using serializers you can integrate this easily with

from rest_framework_gis.serializers import GeoFeatureModelSerializer
from .models import Location, Region

class LocationSerializer(GeoFeatureModelSerializer):
    class Meta:
        model = Location
        fields = ('id', 'name', 'position')
        geo_field = 'position'

class RegionSerializer(GeoFeatureModelSerializer):
    class Meta:
        model = Region
        fields = ('id', 'name', 'area')
        geo_field = 'area'

And they also provide the form alternative

from django import forms
from django.contrib.gis import forms as gis_forms
from .models import Location, Region

class LocationForm(forms.ModelForm):
    position = gis_forms.PointField(widget=gis_forms.OSMWidget(attrs={
        'map_width': 800,
        'map_height': 500,
    }))

    class Meta:
        model = Location
        fields = ['name', 'position']

class RegionForm(forms.ModelForm):
    area = gis_forms.PolygonField(widget=gis_forms.OSMWidget(attrs={
        'map_width': 800,
        'map_height': 500,
    }))

    class Meta:
        model = Region
        fields = ['name', 'area']

Example Requests to Create a Point and a Polygon

Create a Location (Point)

POST /api/locations/
Content-Type: application/json

{
  "name": "Central Park",
  "position": {
    "type": "Point",
    "coordinates": [-56.18816, -34.9011]
  }
}

Create a Region (Polygon)

POST /api/regions/
Content-Type: application/json

{
  "name": "Restricted Zone",
  "area": {
    "type": "Polygon",
    "coordinates": [[
      [-56.18816, -34.9011],
      [-56.19000, -34.9000],
      [-56.18900, -34.9020],
      [-56.18816, -34.9011]
    ]]
  }
}

Example Geospatial Queries

Find the K Nearest Points

from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import Point
from .models import Location

# Define the reference point
reference = Point(-56.18816, -34.9011, srid=4326)

# Find the 5 nearest points
nearest_locations = Location.objects.annotate(
    distance=Distance('position', reference)
).order_by('distance')[:5]

Find Points within a Certain Distance

from django.contrib.gis.measure import D

# Find locations within 1 km of the reference point
nearby_locations = Location.objects.filter(
    position__distance_lte=(reference, D(km=1))
)

Check if a Point is Within a Polygon

from .models import Region

# Check if the point is within any region
point = Point(-56.18816, -34.9011, srid=4326)
regions = Region.objects.filter(area__contains=point)