Consolidate uniqueness constraints which reference nullable fields #11707

Open
opened 2025-12-29 21:48:52 +01:00 by adam · 0 comments
Owner

Originally created by @jeremystretch on GitHub (Oct 9, 2025).

Proposed Changes

There are several instances in NetBox where we define two UniqueConstraints to handle nullable fields: One to handle null values, and one to handle non-null values. The Region model is one example. The UniqueConstraints defined below ensure that the name field is unique to its parent, if one is assigned, or otherwise unique to regions having no parent:

class Meta:
    constraints = (
        # Has no effect if parent is NULL, because PostgreSQL considers NULL != NULL
        models.UniqueConstraint(
            fields=('parent', 'name'),
            name='%(app_label)s_%(class)s_parent_name'
        ),
        # Checks that name is unique if parent is NULL
        models.UniqueConstraint(
            fields=('name',),
            name='%(app_label)s_%(class)s_name',
            condition=Q(parent__isnull=True),
            violation_error_message=_("A top-level region with this name already exists.")
        ),
    ...
    )

PostgreSQL 15 introduced support for declaring NULLS NOT DISTINCT on unique indexes, allowing for the two above constraints to be condensed into one by setting nulls_distinct=False:

class Meta:
    constraints = (
        models.UniqueConstraint(
            fields=('parent', 'name'),
            name='%(app_label)s_%(class)s_parent_name',
            nulls_distinct=False,  # Assert that NULL == NULL
        ),
    ...
    )

NOTE: This is not supported on PostgreSQL versions earlier than 15.

Justification

This will reduce the overall number of unique constraints we have defined, and greatly simplify the logic for ensuring uniqueness where nullable fields must be considered.

Originally created by @jeremystretch on GitHub (Oct 9, 2025). ### Proposed Changes There are several instances in NetBox where we define two UniqueConstraints to handle nullable fields: One to handle null values, and one to handle non-null values. The Region model is one example. The UniqueConstraints defined below ensure that the `name` field is unique to its parent, if one is assigned, or otherwise unique to regions having _no_ parent: ```python class Meta: constraints = ( # Has no effect if parent is NULL, because PostgreSQL considers NULL != NULL models.UniqueConstraint( fields=('parent', 'name'), name='%(app_label)s_%(class)s_parent_name' ), # Checks that name is unique if parent is NULL models.UniqueConstraint( fields=('name',), name='%(app_label)s_%(class)s_name', condition=Q(parent__isnull=True), violation_error_message=_("A top-level region with this name already exists.") ), ... ) ``` [PostgreSQL 15](https://www.postgresql.org/docs/release/15.0/) introduced support for declaring `NULLS NOT DISTINCT` on unique indexes, allowing for the two above constraints to be condensed into one by setting `nulls_distinct=False`: ```python class Meta: constraints = ( models.UniqueConstraint( fields=('parent', 'name'), name='%(app_label)s_%(class)s_parent_name', nulls_distinct=False, # Assert that NULL == NULL ), ... ) ``` **NOTE:** This is not supported on PostgreSQL versions earlier than 15. ### Justification This will reduce the overall number of unique constraints we have defined, and greatly simplify the logic for ensuring uniqueness where nullable fields must be considered.
adam added the type: housekeepingstatus: blockednetbox labels 2025-12-29 21:48:52 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11707