Why would a check constraint be violated on a cascade delete?

60 Views Asked by At

When I delete an object ('item') in my Django app, a related object (in another table) that points to it via a foreign key should also get deleted due to its "on_delete=models.CASCADE" setting. But the cascade delete is failing because of a check constraint on the related model:

MySQLdb.OperationalError: (3819, "Check constraint 'item_or_container' is violated.")

My question is, why would a check constraint be triggered on a delete? Does Django modify the record somehow before deletion?

The record in question does pass the constraint, and if I just delete that record directly it works as expected; it only fails during a cascade delete.

The "violated" constraint is as follows:

models.CheckConstraint(check=Q(item__isnull=False) ^ Q(is_container=True), name='item_or_container')

(Which is an XOR ensuring that an object can EITHER have an assigned item OR be a container - not both.)

My expectation is that both records should simply be deleted. Thank you for your help!

Edit: Here is the 'want' model with the foreign key to the 'item' model:

class Want(models.Model):  # items that a trader wishes to get

    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    trader = models.ForeignKey(Trader, on_delete=models.CASCADE)
    item = models.ForeignKey(Item, null=True, blank=True, default=None, on_delete=models.CASCADE)
    value = models.PositiveIntegerField(default=1, blank=False, validators=[MinValueValidator(1), MaxValueValidator(10)])
    offer_price = models.DecimalField(max_digits=19, decimal_places=4, default=0, blank=True, verbose_name="Cash Offer")
    is_container = models.BooleanField(default=False, blank=True)
    container_name = models.CharField(max_length=100, blank=False)
    num_contained = models.PositiveIntegerField(default=0, blank=False)
    container_limit_num = models.PositiveIntegerField(default=0, blank=False)
    contained_by = models.ForeignKey('self', default=None, null=True, blank=True, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['trader', 'item'], name='unique_want'),
            models.CheckConstraint(check=Q(item__isnull=False) ^ Q(is_container=True), name='item_or_container'),
        ]

(The 'item' model is very simple, with no 'Meta' section, and does not know/care about 'want'.)

I am using Django 4.2.4, and mysqlclient 2.2.0.

0

There are 0 best solutions below