I have a table with a GeoDjango GeometryField, and records include both points and polygons. I need to return those records with Point geometry within a given distance in km from a given point, for an external API. I first filter for Point records, annotate those with a Distance object, then filter for distance.
I find the generation of the filtered
queryset fed to the serializer works fine in my IDE. But when I run the view, it hangs on the annotate() step, with this error:
File "/MyApp/api/views.py", line 102, in get
qs1 = qs0.annotate(distance=Distance('geom', pnt))
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given
What I can't figure out is why I can step through all the lines to create qs2
, as the qs.count()
and qs2 sorted results show, but when I run that code via a URL, it breaks at annotate().
from django.contrib.gis.db import models as geomodels
class PlaceGeom(models.Model):
place = models.ForeignKey(Place,related_name='geoms')
geom = geomodels.GeometryField(null=True, blank=True, srid=4326)
from django.contrib.gis.geos import Polygon, Point
from django.contrib.gis.measure import D, Distance
class SpatialAPIView(generics.ListAPIView):
def get(self, format=None, *args, **kwargs):
params = self.request.query_params
lon = params.get('lon', None)
lat = params.get('lat', None)
dist = params.get('km', None)
pnt = Point(float(lon), float(lat), srid=4326)
print(dist)
>> 3
qs0 = PlaceGeom.objects.extra(where=["geometrytype(geom) LIKE 'POINT'"])
qs0.count()
>> 1887148
qs1 = qs0.annotate(distance=Distance('geom', pnt))
qs2 = qs1.filter(geom__distance_lte=(pnt, D(km=dist))).order_by('distance')
# results are sorted
print(["{:.4f}".format(p.distance.km) for p in qs2][:5])
>> ['0.0635', '0.1071', '0.1283', '0.4274', '1.0647']
filtered = qs2[:pagesize] if pagesize and pagesize < 200 else qs2[:20]
serial = PlaceSerializer
serializer = serial(filtered, many=True, context={
'request': self.request})
serialized_data = serializer.data
result = {
"count": qs.count(),
"type": "FeatureCollection",
"features": serialized_data
}
return JsonResponse(result, safe=False, json_dumps_params={'ensure_ascii': False, 'indent': 2})
This question was answered correctly by @iain-shelvington in his comment. There are two Distance functions in different parts of the django.contrib.gs package. The # of arguments is different for each, as the error indicated.
django.contrib.gis.db.models.function.Distance
was appropriate for annotate() here.