Reputation: 31
I am trying to define a unique constraint for my DB model. I have 3 constraints and have no trouble with 2. But the 3rd one is doing my head a little.
So the model class is fairly simply; its a social media connection request model (between user accounts). These are the constraints I am trying to enforce:
How can I enforce the 3rd constraint here? I initially thought the 1st one enforces the reverse constraint actually (where the uniqueness of the 2 entries in the table are enforced regardless of the order) but it doesnt seem it like (and makes sense too).
class ConnectionRequest(models.Model):
senderAccount = models.ForeignKey(
Account, related_name='sender_Account', on_delete=models.CASCADE)
recipientAccount = models.ForeignKey(
Account, related_name='recipient_Account', on_delete=models.CASCADE)
requested = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.senderAccount.id) + ' to ' + str(self.recipientAccount.id)
class Meta:
constraints = [
# duplicate connection request constraint
models.UniqueConstraint(name='duplicate_connreq_constraint',
fields=['senderAccount', 'recipientAccount']),
# self connection request constraint
models.CheckConstraint(name='self_connection_request_constraint',
check=~models.Q(
senderAccount=models.F("recipientAccount")),
),
]
Upvotes: 1
Views: 1183
Reputation: 477230
Since django-4.0, you could make a functional unique constraint with the Least
[Django-doc] and Greatest
[Django-doc] of the two, so:
from django.db.models.functions import Least, Greatest
class ConnectionRequest(models.Model):
senderAccount = models.ForeignKey(
Account, related_name='sender_Account', on_delete=models.CASCADE
)
recipientAccount = models.ForeignKey(
Account, related_name='recipient_Account', on_delete=models.CASCADE
)
requested = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.senderAccount_id} to {self.recipientAccount_id}'
class Meta:
constraints = [
models.UniqueConstraint(
name='duplicate_connreq_constraint',
fields=['senderAccount', 'recipientAccount'],
),
models.CheckConstraint(
name='self_connection_request_constraint',
check=~models.Q(senderAccount=models.F("recipientAccount")),
),
models.UniqueConstraint(
Least('senderAccount', 'recipientAccount'),
Greatest('senderAccount', 'recipientAccount'),
name='antisymmetric',
),
]
Upvotes: 1