In short: use django queryset extra()
I needed to build a web interface using GeoDjango for querying an existing (huge) PostGIS database table which has a geometry column:
the_geom = models.PointField(srid=4326)
python manage.py inspectdb conveniently created models.py for my django application with the correct class Meta db_table set to the legacy database table name. I just added ‘managed = False‘ so that django does not try to manage the table in any way.
Basically, my application requires the user to upload a KML file containing geometries of interest (e.g. POINT, LINESTRING, etc.), input a distance value in metres, and optional date range parameters.
The application then returns all the points from the database table which are within the user-specified distance and geometries of interest in KML format.
GeoDjango provides two spatial lookup APIs for distance calculation, dwithin and distance. dwithin runs many times faster than distance but it requires the distance to be given in degrees.
PostGIS documentation suggested using geography() and ST_DWithin() for best performance. But, how to I call postGIS geography() in a where-clause from my django application?
I have considered writing a custom manager and using raw() but raw() returns a RawQueryset, which unlike the ordinary Queryset, does not have filter() method (thus chaining of results is not possible). Besides, I would like to make use of postGIS ST_AsKml() on the query result.
Putting everything together:
MyModel.objects.extra(
select={'the_geom_wkt': 'ST_AsText(the_geom)'},
where=[
"ST_DWithin(geography(the_geom), ST_GeographyFromText('SRID=4326;%s'),%%s)"%%geometry_from_kml
],
params=[distance_in_metres],
)