Сформулируйте условный Q на уникальном ограничении для обработки исключений
Django не бросает ValidationError
из-за отсутствующего условия в UniqueConstraint
, и я не знаю, как правильно его сформулировать.
Одна из моих моделей содержит уникальное ограничение, включающее внешний ключ:
class Entry(models.Model):
"""
Entry on a List
"""
name= models.CharField()
expiration_date = models.DateField()
list = models.ForeignKey(List,
related_name="entries",
on_delete=models.CASCADE)
...
class Meta:
constraints = [
UniqueConstraint(fields=['list', 'name'],
name='unique_entry') # Each entry_name may only occur once per list.
]
При отправке новой записи, нарушающей это ограничение, база данных отклоняет запрос и Django выбрасывает необработанное исключение IntegrityError
.
Согласно документации по Django предполагается следующее поведение:
Валидация ограничений
В общем случае ограничения не проверяются во время full_clean(), и не вызывают ошибки ValidationError. Скорее вы получите ошибку целостности базы данных на save(). UniqueConstraints без condition (т.е. нечастичные уникальные ограничения) отличаются в этом отношении тем, что они используют существующую логику validate_unique(), и таким образом обеспечивают возможность двухэтапную валидацию. В дополнение к IntegrityError на save(), ValidationError также возникает во время проверки модели, когда UniqueConstraint нарушается.
Мне нужна ваша помощь в формулировке условия или других предложенных решений для исправления этого поведения. Цель состоит в том, чтобы относиться к UniqueConstraint как к любому другому полю, которое не проходит валидацию: Django бросает ValidationError, который перехватывается Django Rest Framework, и в конечном итоге исходный запрос получит HTTP 400 Bad Request, вместо 500 Internal Server Error.
В идеале я хотел бы реализовать решение, которое позволяет выбрасывать ValidationError
вместо IntegrityError
из модели, вместо того, чтобы прибегать к Serializer
или View
(Альтернативное решение, которого я хотел бы избежать, это запрос к базе данных из View
для проверки уникального ограничения).
Примером может служить condition=Q(name=self.name, list=self.list)
.
Однако я не могу обратиться к экземпляру модели из Meta
:
class Meta:
constraints = [
UniqueConstraint(fields=['list', 'name'],
condition=Q(name=self.name, list=self.list), # this is incorrect
name='unique_entry')
]
Я пытаюсь сделать что-то невозможное? Заранее спасибо, идеи и предложения будут очень признательны.
Вы можете добавить проверку в метод clean
вашей модели. Если вы затем используете ModelForm
, он вызовет метод clean()
и таким образом проверит, является ли элемент действительным.
Таким образом, модель выглядит следующим образом:
from django.core.exceptions import ValidationError
class Entry(models.Model):
name= models.CharField()
expiration_date = models.DateField()
list = models.ForeignKey(
List,
related_name='entries',
on_delete=models.CASCADE
)
def clean(self, *args, **kwargs):
qs = Entry.objects.exclude(pk=self.pk).filter(name=self.name, list_id=self.list_id)
if qs.exists():
raise ValidationError('Can not add an entry with the same name to a list')
return super().clean(*args, **kwargs)
class Meta:
constraints = [
UniqueConstraint(
fields=['list', 'name'],
name='unique_entry'
)
]