5

Django -- Geopy

I am looking for how to define a distance between two points. The first one is related to the post itself and does not change for each post. It indicates the position of the post. The second would be linked to the user's position.

I want to calculate distance btw Post and User.

ISSUE : Assume I get connected : all distance are listed for each post

I got for one post: [459.414, 459.414, 459.414, 0.605, 0.605, 0.605, 0.605, 0.605, 459.414, 0.605] km

user/models.py
        class UserProfile(models.Model):
            ...
            latitude = models.DecimalField(max_digits=9, decimal_places=6, blank=True, default='0')
            longitude = models.DecimalField(max_digits=9, decimal_places=6, blank=True, default='0')

post/models.py
    class Cuisine(models.Model):
         ...
         latitude_user = models.DecimalField(max_digits=9, decimal_places=6, blank=True, default='0')
         longitude_user = models.DecimalField(max_digits=9, decimal_places=6, blank=True, default='0')

Thanks to @tgrandje I've solved some issue to find value from UserProfile: The issue is I always get the same distance for each post. Any advice?

def Homemainpage(request):
    
    post = Cuisine.objects.filter(status=0).order_by('-publishing_date').all() #All cuisine
    
   if request.user.is_authenticated:
    if request.user.userprofile.full_address:
        distance = []
        for p in post:
            post_lon = p.longitude_user
            post_lat = p.latitude_user
        
            post_situation = (post_lon, post_lat)
        
            user_lon = UserProfile.objects.filter(user=request.user)[0].longitude
            user_lat = UserProfile.objects.filter(user=request.user)[0].latitude
            
            user_situation = (user_lon, user_lat)
        
            distance.append(round(geodesic(post_situation, user_situation).km, 3))
    
    # Pre commande pour demain
    #post = Cuisine.objects.filter(status=0).filter(start_date=now().date() + timedelta(days=1)).order_by('-publishing_date').all()
    # En commande pour aujourd'hui
    #post = Cuisine.objects.filter(status=0).filter(start_date=now().date()).order_by('-publishing_date').all()
    
    paginator = Paginator(post, 3)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    listaliments = ListAliments.objects.filter(status=1).all()
    typerepas = Typerepas.objects.filter(status=1).all()
    sperepas = Sperepas.objects.filter(status=1).all()
    
    return render(request, 'index.html', {
        'post': post,
        'listaliments': listaliments,
        'typerepas': typerepas,
        'sperepas': sperepas,
        'page_obj': page_obj,
        'today' : now().date(),
        'tomorrow': now().date() + timedelta(days=1),
        'distance': distance,
    })
Louis
  • 360
  • 2
  • 12
  • Anyone can help me please? – Louis Oct 28 '20 at 17:10
  • 1
    Could you post your view's full code? If you log the calculated distance value, can you see it in your logs/console? – D Malan Oct 29 '20 at 14:57
  • Hi @D Malan that's all I have in my views for this. I've added the geodesic in the head part of my views. The code was working in post/models.py if I wanted to calcul the distance btw post and user of the post. Result = 0 because post localisation = user localisation. My main issue is I want to display the result according to self.request.user. If user A is logging in, the distance needs to take into account his position. – Louis Oct 29 '20 at 15:04
  • If you want me to post something else, I'll be happy to do it :) – Louis Oct 29 '20 at 15:05
  • Do you use a function-based view or class-based view? Why don't return the distance as part of the template's context? – D Malan Oct 29 '20 at 15:24
  • Yo know I'm a beginner with Django that's probably the answer – Louis Oct 29 '20 at 15:26
  • Do you have any idea to solve it? :) – Louis Oct 29 '20 at 15:27
  • 1
    Why would a model have self.request? –  Oct 30 '20 at 20:33
  • @D Malan I've updated my main views – Louis Oct 30 '20 at 20:37
  • @Melvyn do you have any idea to use it in my views? I've updated my post – Louis Oct 30 '20 at 20:38
  • Cuisine.distance_post requires a parameter, request, which you are not passing to the function in the view... – illusion Oct 31 '20 at 04:49
  • No one can correct me with a new code from my Homemainpage (view) ? – Louis Oct 31 '20 at 08:36
  • where is the class if "def distance(self)" is a method? If homemainview is a function based view and you are logined, you can use "request.user". you should use "@login_required" decarator in your view. – Türkalp Nov 03 '20 at 05:16
  • @Türkalp I'll have a look, my goal is to have a main page accessible for everyone and only distance for user who are connected. I don't know I'm not able to get the data userprofile. Do you have any idea on how to change this? – Louis Nov 03 '20 at 13:06
  • Anyone has an idea to avoid this issue? – Louis Nov 06 '20 at 09:06

1 Answers1

0

If you have all latitudes/longitudes ready, you could use pyproj which is really efficient :

from pyproj import Geod
...
user_lon = UserProfile.objects.filter(user=self.request.user).get(self.longitude)
user_lat = UserProfile.objects.filter(user=self.request.user).get(self.latitude)

post_lon = Cuisine.objects.filter(slug=slug).get(self.longitude_user)
post_lat = Cuisine.objects.filter(slug=slug).get(self.latitude_user)

wgs84_geod = Geod(ellps='WGS84')
*_args, dist_meters = wgs84_geod.inv(user_lon,user_lat,post_lon,post_lat)
print(dist_meters)

EDIT

def Homemainpage(request):

  post = Cuisine.objects.filter(status=0).order_by('-publishing_date').all() #All cuisine

  ...
  user_lon = UserProfile.objects.filter(user=request.user)[0].longitude
  user_lat = UserProfile.objects.filter(user=request.user)[0].latitude

  wgs84_geod = Geod(ellps='WGS84')
  kitchen_distance_dict = dict()
  for kitchen in Cuisine.objects.all():
    post_lon = kitchen.longitude
    post_lat = kitchen.latitude
    *_args, dist_meters = wgs84_geod.inv(user_lon,user_lat,post_lon,post_lat)

    kitchen_distance_dict[kitchen.pk] = dist_meters / 1000

  return render(request, 'index.html', {
    'post': post,
    'listaliments': listaliments,
    'typerepas': typerepas,
    'sperepas': sperepas,
    'page_obj': page_obj,
    'distance': kitchen_distance_dict,
  })
tgrandje
  • 2,332
  • 11
  • 33
  • Why the downvote ? The question was "how to define a distance between two points", not about creating the model about the positions... – tgrandje Nov 03 '20 at 12:29
  • Hi @tgrandje thanks for answering me :) the question is: I'm not able to get the data (longitude / latitude) for each UserProfile who get connected to the website. I know how to calculate the distance with Geopy but in my views I'm not able to get it. Do you have any idea? Thanks by the way I did not know about Geod. I'll have a look, – Louis Nov 03 '20 at 13:04
  • 1
    My bad, I had not understood your question, then ! – tgrandje Nov 03 '20 at 13:12
  • If you push user_lon/lat and post_lon/lat in your context, can you display them ? – tgrandje Nov 03 '20 at 13:14
  • No worries, If you have any idea, I'll be very happy :) – Louis Nov 03 '20 at 13:14
  • name 'user_lon' is not defined :( – Louis Nov 03 '20 at 13:16
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/224034/discussion-between-tgrandje-and-louis). – tgrandje Nov 03 '20 at 13:17