Home > Back-end >  how to use Unique Constraint for same models
how to use Unique Constraint for same models

Time:10-28

I want to create only one object for the same users.

class MyModel(models.Model):
    user1 = models.ForeignKey(settings.AUTH_USER_MODEL,...)
    user2 = models.ForeignKey(settings.AUTH_USER_MODEL,...)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=['user1', 'user2'],
                name='user_unique',
            ),
            # UniqueConstraint(
            #     fields=['user2', 'user1'],
            #     name='user_unique2',
            # ),

        ]

I can solve the problem in another way, I just want to know how to do it with UniqueConstraint.

Adding another UniqueConstraint and moving the fields didn't solve the problem.

For example, for users X and Y, I only need one object.

CodePudding user response:

Add a constraint that user1_id should be less than user2_id. In that case if you construct a MyModel, for x and y, user1 will always take the user with the smallest primary key and vice versa:

class MyModel(models.Model):
    user1 = models.ForeignKey(settings.AUTH_USER_MODEL, …)
    user2 = models.ForeignKey(settings.AUTH_USER_MODEL, …)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=['user1', 'user2'],
                name='user_unique',
            ),
            CheckConstraint(
                check=Q(user1_id__lt=F('user2_id')),
                name='asymetric_users',
            ),
        ]

CodePudding user response:

Since Django 4.0 constraints now support expressions, this allows us to use database functions in our constraints allowing us to create a unique constraint with sorted fields:

from django.db.models.functions import Least, Greatest


class MyModel(models.Model):
    user1 = models.ForeignKey(settings.AUTH_USER_MODEL,...)
    user2 = models.ForeignKey(settings.AUTH_USER_MODEL,...)

    class Meta:
        constraints = [
            UniqueConstraint(
                Least("user1", "user2"), Greatest("user1", "user2"),
                name='user_unique',
            )
        ]

CodePudding user response:

There is a simple solution for you called unique_together which does exactly what you want.

Example:

class MyModel(models.Model):
  field1 = models.CharField(max_length=50)
  field2 = models.CharField(max_length=50)

  class Meta:
    unique_together = ('field1', 'field2',)

In your case:

class MyModel(models.Model):
    user1 = models.ForeignKey(settings.AUTH_USER_MODEL,...)
    user2 = models.ForeignKey(settings.AUTH_USER_MODEL,...)

    class Meta:
        unique_together = ('user1','user2',)
  • Related