[Django] 지도 위에 우리나라 행정구역 경계 그리기

김재연·2022년 4월 21일
3

자연재해지도

목록 보기
6/8
post-thumbnail
post-custom-banner

모델 만들기 (MultiPolygonField)

경계를 어떻게 나타낼지 고민하다가 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()로 변경했다.


우리나라 행정구역 좌표 json 파일 구하기

그럼 이제 이 Mark의 MultiPolygonField()에 알맞은 좌표값을 넣어야 한다. 우리나라 좌표값을 일일이 계산할 수는 없으니까 인터넷에서 파일을 구해야한다.

대한민국 행정구역(시도, 시군구) GeoJSON 파일 다운로드 및 SHP 파일 단순화 후 변환 방법 설명

이 방법대로 파일을 만들어도 되는데 (감사하게도) 파일을 첨부해두셨길래 TL_SCCO_CTPRVN.json 을 다운받아서 사용했다. 이 파일을 프로젝트 안에 넣어서 사용한다. (깃에는 안올릴거니까 .gitignoreTL_SCCO_CTPRVN.json을 추가한다.)

이 json 파일은 이렇게 생겼다.


좌표 json 파일 읽어서 DB에 저장하기

이제 이 파일 읽어서 행정구역 좌표를 DB에 저장한다.

0. 코드

# 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')

1. 파일 경로 인식 오류

파일을 읽으려고 경로를 지정하는 부분에서 경로 인식을 못하는 오류가 많이 발생했다. 경로 앞에 r을 붙이래서 속는셈치고 붙여봤는데 이거 붙이니까 잘됐다.


2. json 파일에서 파싱해서 사용할 변수

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번째 지역의 좌표


3. 좌표값으로 MultiPolygon 객체 만들어서 필드에 저장하기

행정구역 이름같은 경우는 단순한 문자열이기 때문에 바로 대입이 가능했지만, 좌표는 MultiPolygon 객체로 만들어서 넣어줘야했다.

geodjango 공식문서에 이 부분을 참고해서

행정구역에 포함된 좌표들을 각각 Polygon 객체 하나로 만든 후, 이 Polygon들을 배열로 이어서 한번에 MultiPolygon의 인자로 넘겨 찍어냈다. 이렇게 만든 MultiPolygon 객체를 Mark 모델의 location 필드에 넘겨주면 완성이다.

🎈 Polygon으로 하지 않고 MultiPolygon으로 한 이유

특별시나 광역시, 강원도 같이 좌표가 전체에 해당하는 한 지역밖에 없는 경우에는 인식이 잘됐지만, 전라도나 충청남도, 경상북도 같이 섬들을 짜잘하게 많이 포함하고 있는 지역은 다각형 하나로 표현하기가 부족했다. MultiPolygon에 좌표를 하나만 넘기면 Polygon도 표현이 가능했기 때문에 따로 모델을 만들지 않고도(물론 모델을 굳이 굳이 따로 만들어보는 삽질은 함) 모두 포함해 나타낼 수 있어 MultiPolygon을 사용했다.


4. url 연결하기

트윗 파이썬 모듈과 마찬가지로 이 모듈도 url에 연결해주고

# urls.py
from .views import BoundarySet

urlpatterns = [
    path('boundary/', BoundarySet.as_view())
]

5. 확인하기

http://127.0.0.1:8000/api/boundary/ 에 접속하고

다시 지도로 돌아가면

짠. 경계가 나눠졌다.

구역을 누르면 그 지역 이름이 뜨고

섬들도 다 잘 나옴

profile
일기장같은 공부기록📝
post-custom-banner

0개의 댓글