我有以下 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")]
如果你写
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',
)
]