Ограничение базы данных на широту и долготу поля PointField с помощью бэкенда MySQL
У меня есть следующая модель Django:
class Place(models.Model):
location = models.PointField(geography=True)
Поле location, похоже, с радостью принимает любое произвольное число для широты и долготы. Даже за пределами +-180 и +-90. Мои исследования говорят, что это происходит из-за того, что SRID не задан в колонке базы данных, хотя база данных была сгенерирована Django. Я считаю, что бэкенд MySQL просто не поддерживает правильную установку SRID на уровне базы данных.
Чтобы предотвратить возникновение проблем, я пытаюсь написать ограничения на поле. Однако, похоже, мне не удается сгенерировать рабочий объект ограничений. Идеальным результатом была бы проверка того, что lat & lng находятся в диапазоне поля extent объекта PointField, но я с радостью соглашусь и на жестко закодированные ограничения.
Альтернативное решение, позволяющее заставить базу данных соблюдать правильные ограничения lat & lng без каких-либо дополнительных ограничений Django, было бы очень признательно.
Я перепробовал множество итераций чего-то подобного. Я не нашел комбинации, которая сделала бы счастливыми и python, и MySQL.
class GeometryPointFunc(Func):
template = "%(function)s(%(expressions)s::geometry)"
def __init__(self, expression: any) -> None:
super().__init__(expression, output_field=FloatField())
class Latitude(GeometryPointFunc):
function = "ST_Y"
class Longitude(GeometryPointFunc):
function = "ST_X"
...
class Meta:
constraints = [models.CheckConstraint(condition=models.Q(Latitude("location")__lte=90), name="lat_lte_extent_lat")]
class Meta:
constraints = [models.CheckConstraint(condition=models.Q(Latitude("location")<=90), name="lat_lte_extent_lat")]
class Meta:
constraints = [models.CheckConstraint(condition=models.Q(90__gte=Latitude("location"), name="lat_lte_extent_lat")]
Если вы напишете Q(foo__lte=bar)
, то компилятор Django ORM в конечном итоге перепишет это в LessThanOrEqual(F('foo'), bar)
, поэтому мы можем использовать это для работы с ограничениями, которые не могут быть (легко) выражены с помощью Q
объектов [Django-doc], мы можем использовать это, чтобы переписать ограничение в:
from django.db.models.lookups import LessThanOrEqual
class Place(models.Model):
# …
class Meta:
constraints = [
models.CheckConstraint(
condition=LessThanOrEqual(Latitude('location'), 90),
name='lat_lte_extent_lat',
)
]