Search code examples
pythondjangodjango-modelsdjango-rest-frameworkdjango-views

how to find near objects in django?


I have a service provider model . it has two fields named : lat & lon

class Provider(models.Model):
    name = models.CharField(max_length=100)
    lat = models.CharField(max_length=20)
    lon = models.CharField(max_length=20)
    address = models.TextField(null=True , blank=True)

    def save(self, *args, **kwargs):
        try:
            data = getaddress(self.lat , self.lon)
            self.address = data['formatted_address']
        except:
            pass
        super(Provider, self).save(*args, **kwargs)

How can i get a location from user and find some service providers that are near to my user? and it must be from the lat and lon field beacuse it is possible to service provider is located on another city ! also the speed of proccesse is important!


Solution

  • Alireza! I have a working idea of how to solve your problem. So, I see a solution via geoip2 library.

    Here you can find information about using this library with django. It`s from django documantation.

    And here one intresting article about related problem. It may be helpful. And I also found a couple of similar problems that have already been discussed. It may be useful to you.

    So. If short, the solution is as follows:

    # Let's assume that you have already created a django project and an application
    
    from django.contrib.gis.geoip2 import GeoIP2
    
    g = GeoIP2()
    
    
    # You`ll need to user IP. For example it possible to get this via some way like that:
    
    def get_client_ip(request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    # After that put response of that function to fallowing:
    
    g.city("72.14.207.99")
    
    {'accuracy_radius': 1000,
     'city': 'Mountain View',
     'continent_code': 'NA',
     'continent_name': 'North America',
     'country_code': 'US',
     'country_name': 'United States',
     'is_in_european_union': False,
     'latitude': 37.419200897216797,
     'longitude': -122.05740356445312,
     'metro_code': 807,
     'postal_code': '94043',
     'region_code': 'CA',
     'region_name': 'California',
     'time_zone': 'America/Los_Angeles',
     'dma_code': 807,
     'region': 'CA'}
    

    You can see that there are latitude and longitude in response. Next, you will only need to compare the received width and longitude with the width and longitude of the provider. For example, you can connect the django-filter module and make a request with filtering by width and longitude fields.

    I hope that my answer helped you a little.

    Adding to the answer:

    import geopy.distance
    
    def find_nearest(user_lat, user_lon):
    
        # We get all the providers' objects and calculate the distance to them
        return Provider.objects.filter(
            # you can add field city or country and use here to immediately reduce the number of objects being checked
        ).annotate(
            distance=Coalesce(# you can use Coalesce or not, the main thing here is the essence of the idea
                geopy.distance.geodesic((lat, lon), (user_lat, user_lon)).km,
                Value(0), output_field=FloatField()
            )
        ).order_by('-distance')[0]