Search code examples
pythondjangopostgisgeodjango

Get random point from django PolygonField


TL,DR; I want to get a random point from a polygon (potentially) using ST_GeneratePoints.


Background

I'm making a GeoDjango web service and have a collection of UK Postcodes with respective boundaries like so:

from django.db import models as dj_models
from django.contrib.gis.db import models as gis_models

class Postcode(gis_models.Model):
      pretty_postcode = dj_models.CharField( max_length=8 )
      coords = gis_models.PolygonField( default='POLYGON EMPTY' )

I've found a delightful little PostGIS function ST_GeneratePoints, which can find me random points in my coords region.

Question

How can I use this function from within my python django app (or can you suggest a better way?). Ideally ending up with a function like so:

from django.contrib.gis import geos
# ... other imports ...

class Postcode(gis_models.Model):
     # ... fields ...

     def get_random_point(self):
         rand_point = # code that executes ST_GeneratePoints
                      # and returns a geos.Point instance
         return rand_point

Solution

  • I have answered a similar question here: Equivalent of PostGIS ST_MakeValid in Django GEOS

    Since you essentially want to call a database function, you cannot quite do it as you imagine.
    What you can do instead is to wrap the ST_GeneratePoints as a GeoFunc:

    from django.contrib.gis.db.models.functions import GeoFunc
    
    class GeneratePoints(GeoFunc):
        function='ST_GeneratePoints'
    

    and use it in an aggregation/annotation:

    from django.db.models import Value
    
    Postcode.objects.annotate(
        rand_point=GeneratePoints(
            'coords',
            Value(1) # to get only one point
        )
    )
    

    Another way of doing the same thing is:

    from django.contrib.gis.db.models.functions import GeoFunc
    from django.db.models import F, Value
    
    Postcode.objects.annotate(
        rand_point=GeoFunc(
            F('coords'),
            Value(1),
            function='ST_GeneratePoints',
        )
    )