raj-kapil
raj-kapil

Reputation: 447

How to override the model's update method in django?

I have a class model which has some fields and I have put up unique constraints on some of those fields. Now my query is I am updating some of my classes status to cancelled, that led me to the error.

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) 

I want to skip this error on model level. How to do that? My custom update method is not getting called, please let me know what I am doing wrong here.

my model

    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.")

Upvotes: 1

Views: 2686

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477607

The .update(…) method [Django-doc] is is not provided by the model, but by the QuerySet. While you can strictly speaking override that, I would advise not to do this.

What you can do is override the clean() method [Django-doc] or .validate_unique(…) [Django-doc] and raise a validation error. If you then use a ModelForm, ModelAdmin, or ModelSerializer, it will show the corresponding error.

We thus can implement this in the model with:

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

If you update it through the Django ORM, then it will not perform validation. In that case you can try to update the object, and catch the exception, so:

from django.db.utils import IntegrityError

try:
    MyModel.objects.filter(…).update(…)
except IntegrityError:
    # …
    # do something
    pass

Upvotes: 1

Related Questions