Django filter location distance with dynamic radius

后端 未结 1 344
终归单人心
终归单人心 2020-12-07 04:56

I have 2 model in django a zone and a shop, models are like this:

from django.contrib.gis.db import models
from django.contrib.gis.geos import Point
from dja         


        
相关标签:
1条回答
  • 2020-12-07 05:39

    That seems to happen inside the MeasureBase class of django.contrib.gis.measure (which Distance/D inherits from) and more specifically in the default_units method where it tries to cast str or numeric input values to float but receives an F expression instead.

    What we can do as a workaround, is to annotate the Distance (careful with this Distance method because it comes from the GeoDjango Geographic Database Functions) between the shop.location_point and the current location_point and then we can filter by that distance being <= than the instance radius:

    from django.contrib.gis.db.models.functions import Distance
    
    zone_list = Zone.objects.annotate(
        distance=Distance('location_point', shop.location_point)
    ).filter(distance__lte=F('radius'))
    

    Kudos to this excellent answer from @e4c5: GeoDjango filter by distance from a model field

    Another approach would be to eliminate the annotation part entirely and go straight to the filtering by Distance:

    from django.contrib.gis.db.models.functions import Distance
    
    zone_list = Zone.objects.filter(
        radius_gte=Distance('location_point', shop.location_point)
    )
    


    I leave this here for comment continuity:

    You can try to cast the F('radius') result as a FloatField() using the Cast() method to turn the Integer to a Float.

    zone_list = Zone.objects.filter(
        location_point__distance_lte=(
            shop.location_point, 
            D(m=Cast('radius', output_field=models.FloatField()))
        )
    )
    

    0 讨论(0)
提交回复
热议问题