You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django 2.2模型中为IntegerRange字段添加同组无重叠唯一约束

Django 2.2 中添加范围不重叠约束的解决方案

首先明确:UniqueConstraint 无法实现范围不重叠的校验逻辑,它仅用于保证字段/字段组合的唯一性。针对你的需求(同一 series、is_island 取值相同的情况下,范围字段不能重叠),需要使用 CheckConstraint 结合 PostgreSQL 的范围操作符来实现。

以下是修改后的完整模型代码:

from django.db import models
from django.contrib.postgres.fields.ranges import IntegerRangeField

class ProjectStructureWbsIslandGap(models.Model):
    series = models.ForeignKey(ProjectStructureFasSeries, on_delete=models.CASCADE)
    is_island = models.BooleanField(default=True) # island or gap
    level_3_range = models.IntegerRangeField(default=(1, 9999)) # 1-9999
    line_number_range = models.IntegerRangeField(default=(1, 9999)) # 1-9999

    class Meta:
        constraints = [
            # 约束1:同一series、is_island下,level_3_range不能重叠
            models.CheckConstraint(
                check=models.Q(
                    ~models.Exists(
                        models.Subquery(
                            models.ProjectStructureWbsIslandGap.objects.filter(
                                series=models.OuterRef('series'),
                                is_island=models.OuterRef('is_island'),
                                id__ne=models.OuterRef('id'),
                                level_3_range__overlap=models.OuterRef('level_3_range')
                            ).values('id')[:1]
                        )
                    )
                ),
                name='level_3_range_no_overlap'
            ),
            # 约束2:同一series、is_island下,line_number_range不能重叠
            models.CheckConstraint(
                check=models.Q(
                    ~models.Exists(
                        models.Subquery(
                            models.ProjectStructureWbsIslandGap.objects.filter(
                                series=models.OuterRef('series'),
                                is_island=models.OuterRef('is_island'),
                                id__ne=models.OuterRef('id'),
                                line_number_range__overlap=models.OuterRef('line_number_range')
                            ).values('id')[:1]
                        )
                    )
                ),
                name='line_number_range_no_overlap'
            ),
        ]

关键逻辑说明:

  • 使用 models.Exists 和 models.Subquery 实现子查询,检查是否存在同条件下范围重叠的其他记录
  • level_3_range__overlap/line_number_range__overlap 是 Django 对 PostgreSQL 范围重叠操作符 && 的封装,用于判断两个区间是否有交集
  • id__ne=models.OuterRef('id') 排除当前记录本身,避免更新时出现自我冲突
  • 两个约束分别对应 level_3_range 和 line_number_range 的校验需求

注意:虽然 Django 2.2 已过时,但 CheckConstraint 是从 2.2 版本开始正式支持的,该方案可在当前版本中正常使用。

内容的提问来源于stack exchange,提问作者Kim Stacks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:35:25