How to make a Django UniqueConstraint that checks fields in a position-independant way?

181 Views Asked by At

I have a Django Model where I'd like to ensure that no duplicate Edge exists where the same pair of Nodes appear as node_a or node_b, in either order.

class Edge(models.Model):
    project = models.ForeignKey(Project, related_name="edges", on_delete=models.CASCADE)
    node_a = models.ForeignKey(Node, related_name="+", on_delete=models.CASCADE)
    node_b = models.ForeignKey(Node, related_name="+", on_delete=models.CASCADE)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=("project", "node_a", "node_b"), name="unique_edge"
            ),
        ]

This catches if an Edge is made with the same (A, B), but not if the same Nodes are put in reverse (B, A).

The validation function I'm trying to port to Constraint`s was:

    def validate_unique(self, *args: Any, **kwargs: Any) -> None:
        if self.project.edges.filter(
            Q(node_a=self.node_a_id, node_b=self.node_b_id)
            | Q(node_a=self.node_b_id, node_b=self.node_a_id)
        ).exists():
            raise ValidationError(
                f"Edges must be unique within a project: {self.node_a_id}|{self.node_b_id}"
            )

This validation function validates that the Nodes are unique in both directions: (A, B) or (B, A).

Is there a way to express this within a UniqueConstraint?

Currently targeting Django 4.1.

0

There are 0 best solutions below