I have a geodjango model with fields

coverage = 10 * 1609.344
reference_point = Point(-72,45) #or some other lat lng
class ServiceArea (geo_models.Model):
    center = geo_models.PointField(default=None, blank=True, null=True)
    radius = models.FloatField(default=floor(6 * 1609.344), null=True, blank=True)  # in meters

I am user center and radius to store a circle representing a service area. I would like to query this to return all objects where the "center" is less than (coverage + radius) away from "reference_point".

Or to put it another way, filter based on any part of the circlular service area being within a certain distance of a reference point.

This is simple with polygonfields, where I can do something like

ServiceArea.objects.filter(polygon__distance_lte=(reference_point, D(m=coverage)))

Although I haven't figured it out yet I imagine it would be possible to store the circles as polygons, and do the calculation as above, but this may have its own problems. And it is simpler for other reasons to just store coordinates and radius in the database to approximate circles.

I've tried using django.db.models.F, but it doesn't seem to work in this situation.

What do you guys think?

  • I still haven't found a way to do with out using some raw sql, which I would prefer not to do. Here are some other links to stackoverflow with similar questions (one unanswered), in case someone else ends up here with the same problem. stackoverflow.com/questions/9547069/… and here is another person with the same question unanswered stackoverflow.com/questions/32609729/… – kennethj Jan 14 '16 at 22:18
  • I don't see any problem with using polygons. You need to represent an area, and polygons are good for that. It would be more flexible in the future too if you changed your service areas to use (e.g) travel times instead of naive radii. – Alexander Jan 19 '16 at 9:01
  • Polygons have a the disadvantage of being harder for users to input, especially on mobile, and often come out looking a little off putting for public consumption, so we are moving away from specific polygons, I have considered using hexa/octa/ngons or something similar. That would approximate a circle. – kennethj Jan 19 '16 at 18:11

Maybe you can achieve this if you use Django 1.9, where you can use the new geographic database functions api.

If you buffer the reference point, then annotate the service areas with the distance to the buffer, and finally filter that distance against the radius.

I am not sure if annotations can be used with F expressions, but if they do, the following query should do what you are looking for (I split the query in two lines here for readability):

from django.contrib.gis.db.models.functions import Distance
from django.db.models import F

# Buffer point with coverage radius (assuming projected coordinates)
reference_buffer = reference_point.buffer(coverage)

# Get service area queryset annotated with distance of center to buffer
qs = ServiceArea.objects.annotate(distance=Distance('center', reference_buffer))

# Filter queryset using the annotated distance
qs = qs.filter(distance__lte=F('radius'))

I don't have a setup like yours at hand, so I can't try this out, but it might work.

  • this setup should work – George Silva Feb 10 '17 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.