Как переопределить метод обновления модели в django?
У меня есть модель класса, которая имеет некоторые поля, и я установил уникальные ограничения на некоторые из этих полей. Теперь мой вопрос заключается в том, что я обновляю статус некоторых классов до отмененного, что привело меня к ошибке.
duplicate key value violates unique constraint "unique-class"
DETAIL: Key (class_id, calendar_date, is_cancelled, cancellation_count)=(6-9Hip523, 2021-10-27, t, 0)
Я хочу пропустить эту ошибку на уровне модели. Как это сделать? Мой пользовательский метод обновления не вызывается, пожалуйста, дайте мне знать, что я делаю неправильно.
моя модель
class Meta:
constraints = [
models.UniqueConstraint(fields=['class_id', 'calendar_date', 'is_cancelled', 'cancellation_count'],
name='unique-class')
]
def update(self, *args, **kwargs):
if self.is_cancelled:
try:
super().update(*args, **kwargs)
except:
print("Classes are already cancelled.")
Метод .update(…)
[Django-doc] предоставляется не моделью, а QuerySet
. Хотя, строго говоря, вы можете переопределить его, я бы советовал не делать этого.
Вы можете переопределить метод clean()
[Django-doc] или .validate_unique(…)
[Django-doc] и вызвать ошибку валидации. Если вы затем используете ModelForm
, ModelAdmin
или ModelSerializer
, то будет показана соответствующая ошибка.
Таким образом, мы можем реализовать это в модели следующим образом:
from django.core.exceptions import ValidationError
class MyModel(models.Model):
def validate_unique(self, *args, **kwargs):
qs = MyModel.objects.exclude(pk=self.pk).filter(
class_id=self.class_id,
calendar_date=self.calendar_date,
is_cancelled=self.is_cancelled,
cancellation_count=self.cancellation_count
).exists()
if qs:
raise ValidationError('Classes are already cancelled')
return super().validate_unique(*args, **kwargs)
class Meta:
# …
pass
Если вы обновляете его через Django ORM, то он не будет выполнять валидацию. В этом случае вы можете попытаться обновить объект и поймать исключение, так:
from django.db.utils import IntegrityError
try:
MyModel.objects.filter(…).update(…)
except IntegrityError:
# …
# do something
pass