使用 MySQL 后端对 PointField 的纬度和经度进行数据库约束

问题描述 投票:0回答:1

我有以下 Django 模型:

class Place(models.Model):
    location = models.PointField(geography=True)

位置字段似乎很乐意接受任意数字的纬度和经度。甚至超过 +-180 和 +-90 的限制。我的研究表明,这是由于 SRID 未在数据库列中设置,即使数据库是由 Django 生成的。我确实相信 MySQL 后端不支持在数据库级别正确设置 SRID。

为了防止出现任何问题,我正在尝试在该字段上写约束。但是,我似乎无法生成工作约束对象。完美的结果是检查纬度和经度是否在 PointField 对象的范围字段范围内,但我也很乐意接受硬编码的限制。

或者,如果有一个解决方案使数据库尊重正确的纬度和经度限制,而不需要任何额外的 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")]
django django-models geodjango
1个回答
0
投票

如果你写

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',
            )
        ]
© www.soinside.com 2019 - 2024. All rights reserved.