Geo๐Django์ ํจ๊ป ์ผํ๊ธฐ
์ด ํํ ๋ฆฌ์ผ์ ๋ชฉ์
๋ณ๊ฑฐ ์๋๋ฐ, ์ฌ๊ธฐ์์๋ ๊ตญ๊ฐ์ ๋์ ์ด๋ฆ์ ์ ๋ ฅํ์ฌ ์์น ์ขํ(๊ฒฝ๋, ์๋)๋ฅผ ์ป์ต๋๋ค.
์๊ตฌ ์ฌํญ:
postgis ํ์ฅ์ด ํ์ํฉ๋๋ค.
postgres์ ์ค์น๋จ
QGIS ์ง์ค์ฅ๊ณ
์ข ์์ฑ ๋๋ ์ง๋ฆฌ ๊ณต๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์นGEOS, GDAL, and PROJ.4 ,
Note: above requirements need to be install on your machine seperately before continuing
ํ๋ก์ ํธ ์ค์ :
$ mkdir dj_gis && cd dj_gis
$ python3 -m venv env
$ source env/bin/activate
$ pip install django djangorestframework django-leaflet geopy psycopg2-binary
$ django-admin.py startproject config
$ python manage.py startapp location
๊ตฌ์ฑ/settings.py
#config/settings.py
INSTALLED_APPS = [
"django.contrib.gis",
"location",
"rest_framework",
]
๊ตฌ์ฑ/urls.py
#config/urls.py
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/", include("location.urls")),
]
์์น ์ฑ์ url.py ํ์ผ ํฌํจ
#location/urls.py
from django.urls import path
urlpatterns = []
So we finished basic setups
๋ชจ๋ธ location/models.py๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
from django.db import models
from django.contrib.gis.db import models # GeoDjango Model
from django.utils.translation import gettext_lazy as _
class Hotel(models.Model):
name = models.CharField(max_length=255)
street_1 = models.CharField(max_length=200)
street_2 = models.CharField(max_length=200, null=True, blank=True)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
country = models.CharField(max_length=50)
location = models.PointField(null=True) # Spatial Field
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = _("Hotel")
verbose_name_plural = _("Hotels")
def __str__(self):
return f"{self.street_1}, {self.city}, {self.state}, {self.country}"
here, we include a pointfield spatial field of geo django model api.
์ฐ๋ฆฌ ๋ชจ๋ธ์ ๋ํ ์ง๋ ฌ ๋ณํ๊ธฐ์ ๋ทฐ๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
# location/serializers.py
from location.models import Hotel
from rest_framework import serializers
class HotelSerializer(serializers.ModelSerializer):
class Meta:
model = Hotel
fields = (
"id",
"name",
"street_1",
"street_2",
"city",
"state",
"zip_code",
"country",
"location",
)
extra_kwargs = {"location": {"read_only": True}}
์์น/views.py
from location.serializers import HotelSerializer
from django.shortcuts import render
from rest_framework import generics
from .models import Hotel
from django.contrib.gis.geos import Point
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="location")
class ListCreateGenericViews(generics.ListCreateAPIView):
queryset = Hotel.objects.all()
serializer_class = HotelSerializer
def perform_create(self, serializer):
street_1 = serializer.initial_data["street_1"]
address = serializer.initial_data["city"]
state = serializer.initial_data["state"]
country = serializer.initial_data["city"]
data = [street_1, address, state, country]
" ".join(data)
g = geolocator.geocode(data)
lat = g.latitude
lng = g.longitude
pnt = Point(lng, lat)
print(pnt)
serializer.save(location=pnt)
class HotelUpdateRetreiveView(generics.RetrieveUpdateDestroyAPIView):
queryset = Hotel.objects.all()
serializer_class = HotelSerializer
def perform_update(self, serializer):
street_1 = serializer.initial_data["street_1"]
address = serializer.initial_data["city"]
state = serializer.initial_data["state"]
country = serializer.initial_data["city"]
data = [street_1, address, state, country]
" ".join(data)
g = geolocator.geocode(data)
lat = g.latitude
lng = g.longitude
pnt = Point(lng, lat)
print(pnt)
serializer.save(location=pnt)
Note: above view can be further refactor using viewsets or your desired ones.
๊ทธ๋์ geopy ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ์ฉํฉ๋๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ฌ๋ฌ ์ง์ค์ฝ๋ฉ ์น ์๋น์ค๋ฅผ ์ํ Python ํด๋ผ์ด์ธํธ์ ๋๋ค. geopy๋ฅผ ์ฌ์ฉํ๋ฉด Python ๊ฐ๋ฐ์๊ฐ ํ์ฌ ์ง์ค์ฝ๋ ๋ฐ ๊ธฐํ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ธ๊ณ์ ์ฃผ์, ๋์, ๊ตญ๊ฐ ๋ฐ ๋๋๋งํฌ์ ์ขํ๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ์์ต๋๋ค.
URL์ ์ ๋ฐ์ดํธํด ๋ณด๊ฒ ์ต๋๋ค.
#location/urls.py
from django.urls import path
from .views import HotelUpdateRetreiveView, ListCreateGenericViews
urlpatterns = [
path("hotels", ListCreateGenericViews.as_view()),
path(
"hotels/<str:pk>",
HotelUpdateRetreiveView.as_view(),
),
]
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ:
sudo -u postgres psql
CREATE DATABASE locator;
CREATE USER locator WITH PASSWORD 'locator';
CREATE EXTENSION postgis;
ALTER ROLE locator SET client_encoding TO 'utf8';
ALTER ROLE locator SET default_transaction_isolation TO 'read committed';
ALTER ROLE locator SET timezone TO 'UTC';
ALTER ROLE locator SUPERUSER;
GRANT ALL PRIVILEGES ON DATABASE locator TO locator;
settings.py์์ ๋ช ๊ฐ์ง๋ฅผ ๋ณ๊ฒฝํด ๋ณด๊ฒ ์ต๋๋ค.
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.gis",
"location",
"rest_framework",
"leaflet",
]
DATABASES = {
"default": {
"ENGINE": "django.contrib.gis.db.backends.postgis",
"NAME": "locator",
"USER": "locator",
"PASSWORD": "locator",
"HOST": "localhost",
"PORT": "5432",
}
}
LEAFLET_CONFIG = {
# "SPATIAL_EXTENT": (5.0, 44.0, 7.5, 46),
"DEFAULT_CENTER": (13.3888599 52.5170365), #set your corordinate
"DEFAULT_ZOOM": 16,
"MIN_ZOOM": 3,
"MAX_ZOOM": 20,
"DEFAULT_PRECISION": 6,
"SCALE": "both",
"ATTRIBUTION_PREFIX": "powered by me",
}
๊ด๋ฆฌ์์ ๋ชจ๋ธ ๋ฑ๋ก
from django.contrib import admin
from leaflet.admin import LeafletGeoAdmin
from .models import Hotel
@admin.register(Hotel)
class HotelAdmin(LeafletGeoAdmin):
list_display = ("id", "name", "location", "created_at", "updated_at")
so, we have added leaflet, leaflet_config and database.
For more about Leaflet you can visit Read the docs
์ฑ์ ์คํํด ๋ด ์๋ค:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
์ฌ๊ธฐ, ๊ด๋ฆฌ์ ํจ๋์์ ์ป๋ ๊ฒ.
ํ์ ๊ฐ๋ฅํ API๋ฅผ ์ฌ์ฉํ์ฌ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ฐํธ ๋ฐฐ๋ฌ๋ถ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Try it out yourself for udate and delete
github repo์์ ์ฝ๋๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
๋ฆฌ์ผ๋ง / dj_gis
django๋ฅผ ์ฌ์ฉํ๋ GIS์ ์
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(Geo๐Django์ ํจ๊ป ์ผํ๊ธฐ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/lyamaa/working-with-geo-django-32ndํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค