Skip to content

Support row-level check constraints (CheckConstraint) on Custom Object Types #674

Description

@bctiemann

Plugin Version

v0.6.0

Proposed functionality

Add a way to declare an arbitrary cross-field boolean predicate on a Custom Object Type, backed by a Postgres CheckConstraint. Two possible shapes, either of which would work:

  • an optional check predicate on each entry of the constraints block proposed for compound/partial uniqueness, mirroring the condition convention proposed there, or
  • a CUSTOM_VALIDATORS-style JSON dict embedded per-COT in the portable schema.

Today there is no check / CheckConstraint concept anywhere in cot_schema_v1.json, format.py, or models.py.

Use case

netbox-lifecycle's SupportContractAssignment / LicenseAssignment use a CheckConstraint to require that an assignment reference exactly one of a Device or a VirtualMachine, or neither, but never both:

models.CheckConstraint(
    condition=(
        models.Q(device__isnull=True, virtual_machine__isnull=False)
        | models.Q(device__isnull=False, virtual_machine__isnull=True)
        | models.Q(device__isnull=True, virtual_machine__isnull=True)
    ),
    ...
),

Note that this specific "either/or" pattern is often better modeled in Custom Objects today with a single polymorphic object field rather than two nullable FKs plus a check constraint — so this particular example isn't itself blocking. But arbitrary cross-field predicates in general (e.g. "end_date > start_date", or "if kind='wan' then bandwidth_mbps > 0") have no COT-native equivalent at all; today they'd have to live in clean() or CUSTOM_VALIDATORS, neither of which travels through the portable schema. This is a lower-priority gap than compound/partial uniqueness — only 1 of 9 surveyed plugins is blocked by it, and only in a case that has a cleaner COT-native workaround.

External dependencies

None. Lower priority than the compound- and partial-uniqueness constraint features; worth designing consistently with those if pursued.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions