Django에서 DBMS를 MySQL 8.0을 사용할 때 Django Point나 PointField의 srid를 4326으로 설정하더라도 행을 생성한 후 MySQL에서 확인해보면 point 필드의 srid가 0이 되는 문제가 발생한다. django.contrib.gis.db.models.functions.Distance
를 사용할 때, 필드 값과 Point 객체를 비교할 때도 생성된 임시 Point 객체의 srid 값이 MySQL 쿼리 상에서 0이 된다.
SRID should be stored in DB on MySQL backend
SRID issues with GeoDjango on MySQL 8
Add OGC-compliant models for GeoDjango running on MySQL 8.0
django.contrib.gis.db.backends.mysql
내부 코드를 보면 아래와 같다.
# django\\contrib\\gis\\db\\backends\\base\\operations.py
elif self.connection.features.has_spatialrefsys_table:
return "%s(%%s,%s)" % (self.from_text, f.srid)
else:
# For backwards compatibility on MySQL (#27464).
return "%s(%%s)" % self.from_text
해당 backend의 has_spatialrefsys_table
클래스 변수가 True로 설정되어야 Point 객체나 필드를 SQL로 변환할 때 srid가 반영된다.
(예시)
ST_GeomFromText('POINT(127.0256913 37.58582547, 4326)')
근데 MySQL은 has_spatialrefsys_table
가 False로 설정되어 있다. 따라서 항상 MySQL에 전달하는 SQL에는 srid가 설정되어 있지 않아 0으로 자동 대입되는 것이다.
# django\\contrib\\gis\\db\\backends\\mysql\\features.py
class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
has_spatialrefsys_table = False
supports_add_srs_entry = False
supports_distance_geodetic = False
supports_length_geodetic = False
supports_area_geodetic = False
supports_transform = False
supports_null_geometries = False
supports_num_points_poly = False
unsupported_geojson_options = {"crs"}
근본적으로 Django의 backend 차원에서 업데이트가 이루어져야 한다. 일단 Django 4.1부터는 MySQL 5.7 버전의 지원을 종료하므로 이제 본격적인 개선이 이루어질 것이다.
임시적으로, MySQL INSERT 쿼리를 통해 DB에 저장되는 값에 SRID를 부여하고, Django에서 관련 쿼리를 호출할 때 ORM 대신 rawSQL을 사용할 수 있다.
혹은 MySQL 상의 point 필드 srid는 모두 0으로 두고, 거리 계산 등 srid 관련 작업이 필요할 때는 geopy
패키지를 이용한다.
Geographic Database Functions | Django documentation | Django