경계를 어떻게 나타낼지 고민하다가 geodjango에서 사용할 수 있는 필드인 polygonfield을 이용하기로 했다. 이전에 만들어놓았던 Mark 모델(핀)을 활용해서 만들었다. 기존의 Mark 모델은 Pointfield
을 사용해서 지도 위의 한 점에 핀이 꽂히는거까지 보이는 상태였다.
# models.py
class Mark(models.Model):
name = models.CharField(max_length=255)
location = gismodels.MultiPolygonField()
def __str__(self):
return self.name
class Tweet(BaseModel):
twid = models.TextField()
time = models.TextField()
text = models.TextField()
user = models.TextField()
disaster_tag = models.ForeignKey(DisasterTag, on_delete=models.CASCADE)
location = models.ForeignKey(Mark, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return str(self.disaster_tag) + " - " + str(self.text)
Tweet이 지도 위에 꽂힌 핀인 Mark를 ForeignKey로 잡는다. Mark 핀을 다각형 모양으로 나타내서 우리나라 행정구역을 그릴 생각이다. 처음에는 PolygonField()
로 했다가 우리나라가 섬이 많아서 충청남도, 전라도 등이 다각형 하나로 표현하기에는 부족하기 때문에 MultiPolygonField()
로 변경했다.
그럼 이제 이 Mark의 MultiPolygonField()
에 알맞은 좌표값을 넣어야 한다. 우리나라 좌표값을 일일이 계산할 수는 없으니까 인터넷에서 파일을 구해야한다.
대한민국 행정구역(시도, 시군구) GeoJSON 파일 다운로드 및 SHP 파일 단순화 후 변환 방법 설명
이 방법대로 파일을 만들어도 되는데 (감사하게도) 파일을 첨부해두셨길래 TL_SCCO_CTPRVN.json
을 다운받아서 사용했다. 이 파일을 프로젝트 안에 넣어서 사용한다. (깃에는 안올릴거니까 .gitignore
에 TL_SCCO_CTPRVN.json
을 추가한다.)
이 json 파일은 이렇게 생겼다.
이제 이 파일 읽어서 행정구역 좌표를 DB에 저장한다.
# views.py
class BoundarySet(APIView):
def get(self, request):
file_path = r"./TL_SCCO_CTPRVN.json"
with open(file_path, 'r', encoding="UTF8") as file:
data = json.load(file)
for i in range(len(data["features"])):
print(data["features"][i]["properties"]["CTP_KOR_NM"], " 정보 표시됨")
polys = []
for j in range(len(data["features"][i]["geometry"]["coordinates"])):
polys.append(Polygon(data["features"][i]["geometry"]["coordinates"][j]))
poly = MultiPolygon(polys)
mark_kr = Mark(
name = data["features"][i]["properties"]["CTP_KOR_NM"],
location=poly
)
mark_kr.save()
print("file open success")
return render(request, 'index.html')
파일을 읽으려고 경로를 지정하는 부분에서 경로 인식을 못하는 오류가 많이 발생했다. 경로 앞에 r
을 붙이래서 속는셈치고 붙여봤는데 이거 붙이니까 잘됐다.
len(data["features"])
: 저장된 행정구역의 수
data["features"][i]["properties"]["CTP_KOR_NM"]
: 행정구역 이름(국문)
len(data["features"][i]["geometry"]["coordinates"])
: i번째 행정구역에 포함된 지역의 수
data["features"][i]["geometry"]["coordinates"][j]
: i번째 행정구역의 j번째 지역의 좌표
행정구역 이름같은 경우는 단순한 문자열이기 때문에 바로 대입이 가능했지만, 좌표는 MultiPolygon
객체로 만들어서 넣어줘야했다.
geodjango 공식문서에 이 부분을 참고해서
행정구역에 포함된 좌표들을 각각 Polygon
객체 하나로 만든 후, 이 Polygon
들을 배열로 이어서 한번에 MultiPolygon
의 인자로 넘겨 찍어냈다. 이렇게 만든 MultiPolygon
객체를 Mark 모델의 location 필드에 넘겨주면 완성이다.
🎈 Polygon으로 하지 않고 MultiPolygon으로 한 이유
특별시나 광역시, 강원도 같이 좌표가 전체에 해당하는 한 지역밖에 없는 경우에는 인식이 잘됐지만, 전라도나 충청남도, 경상북도 같이 섬들을 짜잘하게 많이 포함하고 있는 지역은 다각형 하나로 표현하기가 부족했다. MultiPolygon에 좌표를 하나만 넘기면 Polygon도 표현이 가능했기 때문에 따로 모델을 만들지 않고도(물론 모델을 굳이 굳이 따로 만들어보는 삽질은 함) 모두 포함해 나타낼 수 있어 MultiPolygon을 사용했다.
트윗 파이썬 모듈과 마찬가지로 이 모듈도 url에 연결해주고
# urls.py
from .views import BoundarySet
urlpatterns = [
path('boundary/', BoundarySet.as_view())
]
http://127.0.0.1:8000/api/boundary/
에 접속하고
다시 지도로 돌아가면
짠. 경계가 나눠졌다.
구역을 누르면 그 지역 이름이 뜨고
섬들도 다 잘 나옴