میثاق لطفی
میثاق لطفی
خواندن ۳ دقیقه·۵ سال پیش

کار با موقعیت مکانی در جنگو

سلام اول از همه چیز این اولین تجربه بلاگ نویسی توی ویرگول هست که امیدوارم مفید باشه.

همونطور که از عنوان مشخص هست میخواهیم مقداری با داده های جغرافیایی در فریمورک جنگو کار کنیم و با یک مثال کوچک یک دید کلی به نحوه کار داشته باشیم.

فرض کنید در حال ساخت برنامه ای هستید که یک سری شعبه ها از رستوران در مناطق مختلف شهر وجود دارد و میخواهید نزدیک ترین شعبه ها رو با توجه موقعیت مکانی کاربر بهش نشون بدید. در اینجا با این مثال بصورت خیلی کلی و کوچک پیش میریم تا ببینیم چجور میشه همچین چیزی را پیاده کرد.


پیش نیاز ها

اول از همه چیز نیاز داریم که افزونه را روی دیتابیس پستگرس نصب بکنید تا بتونه با داده های جغرافیایی کار کنه، اسم این افزونه Postgis هست، برای نصب این افزونه کافیه یک سرچ ساده بزنید و نحوه نصب برای سیستم عامل های مختلف را میاره.

برای نمونه برای سیستم عامل مک به این شیوه هست:

$ brew install gdal $ brew install libgeoip

وقتی که نصب شد باید به دیتابیسی که از قبل برای پروژه جنگو ساختید وصل بشید:

psql DATABASE_NAME

و با دستور :

`CREATE EXTENSION IF NOT EXISTS postgis;`

این افزونه را روی دیتابیس فعال کنید.

حالا باید جنگو را تنظیم کنیم که امکانات کار با این داده ها را برای ما فراهم کنه. برای اینکار فایل settings.py را باز کنید و در بخش تنظیمات دیتابیس گزینه ENGINE را به:

'django.contrib.gis.db.backends.postgis'

تغییر بدید.

در نهایت باید همچین چیزی بشه:

DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', 'NAME': DATABASE_NAME, 'USER': DATABASE_USER, 'PASSWORD': DATABASE_PASSWORD, 'HOST': DATABASE_HOST, 'PORT': 'DATABASE_PORT', } }

همچنین در بخش INSTALLED_APPS باید django.contrib.gis را اضافه کنید:

INSTALLED_APPS = [ ... 'django.contrib.gis', ... ]

راه اندازی مدل ها به کمک فیلدهای GeoDjango

حالا وقتش رسیده که مدل ها را درست کنیم. همونطور که اول مطلب گفتم سناریو اینه که یکسری شعبه های رستوران در نقاط مختلف شهر وجود دارد که قرار است با توجه به نزدیک بودن به موقعیت مکانی کاربر به ترتیب نشان داده بشوند.

from django.contrib.gis.db import models class Branch(models.Model): name = models.CharField(max_length=100) location = models.PointField()

این مدل شعبه هست که بطور ساده یک نام دارد و یک مختصات مکانی، که نقطه جغرافیایی شعبه رو مشخص میکنه. حالا کافیه مایگرشن را انجام بدین تا توی دیتابیس ساخته بشه.

برای ساخت یک نقطه جغرافیایی (PointField) به دو عدد طول (longitude) و عرض (latitude) جغرافیایی نیاز داریم.

شیوه ساختن یک نقطه به شکل زیر هست:

from django.contrib.gis.geos import Point latitude = 17.58207 longitude = 141.05398 # ساخت نقطه جغرافیایی با نقاط بالا point = Point(float(longitude), float(latitude), srid=4326) # ساخت یک نمونه شعبه جدید branch = Branch() branch.location = point branch.name = 'نام شعبه ۱' branch.save()

خب حالا یک شعبه ساختیم که مکانش هم بطور دقیق مشخص کردیم، شما میتونید چندتا بسازید با نقاط مختلف.

با این کار خیلی ساده میتونیم فاصله کاربر تا نقطه را مشخص کنیم:

from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.geos import Point # از داخل درخواستی که دریافت شده نقاط را میگیریم: latitude = request.query_params.get('latitude') longitude = request.query_params.get('longitude') # با استفاده از اعداد بالا نقطه جغرافیایی کاربر را میسازیم point_of_user = Point(float(longitude), float(latitude), srid=4326) # نزدیکترین شعبه ها به موقعیت کاربر را دریافت میکنیم branches = Branch.objects.filter().annotate(distance=Distance('location', point_of_user)).order_by('distance')

به همین راحتی تونستیم طبق مکان کاربر شعبه هارو بهش نشون بدیم که اپ را خیلی کاربرپسند تر میکنه. بعنوان نکته پایانی با این کد هم میشه فاصله دو نقطه را در واحد کیلومتر دریافت کرد:

روش اول:

from geopy.distance import distance as geopy_distance distance = geopy_distance(POINT1, POINT2).kilometers

کد بالا نیازمند نصب پکیج geopy هست که امکانات بیشتری هم در اختیارمون میذاره:

pip install geopy

روش دوم:

بدون نصب پکیج بالا هم به اینصورت میشه:

distance = point1.distance(point2) distance_in_km = distance * 100

به همین راحتی و باحالی :) نظرات و پیشنهادات خودتون را با من درمیان بگذارید.

میتونید در تلگرام هم دنبال کنید.

جنگوdjangogeodjangoجغرافیاییpostgis
برنامه نویس بک اند، علاقه مند به علم و یادگیری چیزها
شاید از این پست‌ها خوشتان بیاید