Skip to content

Support compound (multi-field) uniqueness constraints on Custom Object Types #669

Description

@bctiemann

Plugin Version

v0.6.0

Proposed functionality

Add support for compound (multi-field) uniqueness constraints at the Custom Object Type level — exposed via the UI, the REST API, and the portable schema — backed by a real Postgres UniqueConstraint on the generated table. Today, CustomObjectTypeField only supports a scalar per-field unique boolean; there is no CustomObjectTypeConstraint / unique_together concept on CustomObjectType, and the portable schema (cot_schema_v1.json) has no way to express a multi-column constraint.

In rough order of frequency of use across surveyed plugins, the design should cover:

  1. Plain multi-field uniqueness (UniqueConstraint(fields=[...]) / unique_together) — needed by every surveyed plugin.
  2. Uniqueness over a functional expression, e.g. case-insensitive uniqueness via UniqueConstraint(Lower('name')) — used by netbox-lifecycle (SupportSKU, SupportContract, License, Vendor).
  3. Uniqueness spanning both halves of a polymorphic/GFK-style reference (object_type + object_id) — used by netbox-lifecycle's HardwareLifecycle, netbox-attachments' Assignment, and netbox-acls' ACLAssignment.

Use case

This is the single most common structural blocker preventing NetBox plugins from being modeled with Custom Objects instead of a full plugin. Of 9 model-defining plugins surveyed (netbox-inventory, netbox-lifecycle, netbox-physical-geometry, netbox-documents, netbox-attachments, netbox-acls, netbox-contract, netbox-public-clouds, slurpit_netbox), 8 rely on compound uniqueness at least once — for example:

  • CloudAccount(cloud_platform, account_id) — netbox-public-clouds
  • Asset(device_type, serial), Purchase(supplier, name) — netbox-inventory
  • ACLRule(access_list, sequence) — netbox-acls
  • Floorplan(location, name) — netbox-physical-geometry

Without this, none of these plugins' data models can be fully replaced by Custom Objects, which directly undercuts the core goal of Custom Objects: reducing the surface area of data-model extensions that require a full plugin.

External dependencies

None. Implementable with Django's existing UniqueConstraint support and the schema executor's existing raw-DDL machinery (connection.schema_editor()).

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