Как использовать уникальное ограничение для одинаковых моделей

Я хочу создать только один объект для одних и тех же пользователей.

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',
            # ),

        ]

Я могу решить проблему другим способом, я просто хочу знать, как это сделать с помощью UniqueConstraint.

Добавление еще одного UniqueConstraint и перемещение полей не решило проблему.

Например, для пользователей X и Y мне нужен только один объект.

Добавьте ограничение, что user1_id должен быть меньше user2_id. В таком случае, если вы построите MyModel, для x и y, user1 всегда будет брать пользователя с наименьшим первичным ключом, и наоборот:

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',
            ),
        ]

Для вас есть простое решение под названием unique_together, которое делает именно то, что вы хотите.

Пример:

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

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

В вашем случае:

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

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

Поскольку ограничения Django 4.0 теперь поддерживают выражения, это позволяет нам использовать функции базы данных в наших ограничениях, что позволяет нам создать уникальное ограничение с отсортированными полями:

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',
            )
        ]
Вернуться на верх