Django - Убедитесь, что два поля в таблице одного типа модели не имеют одинакового значения для сущности

Итак, у меня есть класс пользователя, и пользователь может следить за другим пользователем, но я не хочу, чтобы пользователь мог следить за собой. Есть ли способ добавить это ограничение в Django?

class FollowUser(AbstractSimpleModel):
    follower_id = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower_id')
    followee_id = models.OneToOneField(User, on_delete=models.CASCADE, related_name='followee_id')

Поскольку вам нужно проверить значение поля на основе значений других полей, а именно FollowUser.follower_id и FollowUser.followee_id, вы можете следовать этому процессу, как Django обрабатывает проверку полей следующим образом:

  1. Implement Model.clean() where you would run the validation

  2. Override Model.save() to call the complete validation process via Model.full_clean(). This explicit step is needed because as documented:

    Note that full_clean() will not be called automatically when you call your model’s save() method. You’ll need to call it manually when you want to run one-step model validation for your own manually created models. For example:

from django.core.exceptions import ValidationError
from django.db import models


class UserDummy(models.Model):
    pass

class FollowUser(models.Model):
    follower_id = models.ForeignKey(UserDummy, on_delete=models.CASCADE, related_name='follower_id')
    followee_id = models.OneToOneField(UserDummy, on_delete=models.CASCADE, related_name='followee_id')

    def clean(self):
        if self.follower_id == self.followee_id:
            raise ValidationError("Users can't follow themselves")

    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)

Выборочный запуск

Установите данные:

>>> from my_app.models import *
>>> UserDummy.objects.values()
<QuerySet [{'id': 1}, {'id': 2}, {'id': 3}]>
>>> user1 = UserDummy.objects.get(id=1)
>>> user2 = UserDummy.objects.get(id=2)
>>> user3 = UserDummy.objects.get(id=3)

Неудачная валидация:

>>> # Using Model.save()
>>> FollowUser(follower_id=user1, followee_id=user1).save()
Traceback (most recent call last):
    raise ValidationError(errors)
django.core.exceptions.ValidationError: {'__all__': ["Users can't follow themselves"]}
>>> 
>>> # Using Model.objects.create()
>>> FollowUser.objects.create(follower_id=user1, followee_id=user1)
Traceback (most recent call last):
    raise ValidationError(errors)
django.core.exceptions.ValidationError: {'__all__': ["Users can't follow themselves"]}

Успешная валидация:

>>> # Using Model.save()
>>> FollowUser(follower_id=user1, followee_id=user2).save()
>>> 
>>> # Using Model.objects.create()
>>> FollowUser.objects.create(follower_id=user2, followee_id=user3)
<FollowUser: FollowUser object (2)>
>>> 
>>> FollowUser.objects.values()
<QuerySet [{'id': 1, 'follower_id_id': 1, 'followee_id_id': 2}, {'id': 2, 'follower_id_id': 2, 'followee_id_id': 3}]>

Примечание: Имейте в виду, что если вы используете Model.objects.bulk_create(), вам потребуются дальнейшие изменения, поскольку он не вызывает функциональность Model.save(), как описано в документации:

bulk_create()

.

Метод сохранения модели save() не будет вызван, и сигналы pre_save и post_save не будут отправлены.

Вернуться на верх