Search code examples
djangomodelforeign-keys

FOREIGN KEY constraint failed while trying to delete an object related


So I have these models in my app:

from django.db import models
from accounts.models import Vendedor


class Comissao(models.Model):
    porcentagem = models.FloatField()


    def __str__(self):
        return str(self.porcentagem)


class Venda(models.Model):
    vendedor = models.ForeignKey(Vendedor, on_delete=models.DO_NOTHING)
    comissao_venda = models.ForeignKey(Comissao, on_delete=models.DO_NOTHING)
    data_venda = models.DateField(auto_now_add=True)
    valor_venda = models.FloatField()
    descricao_venda = models.CharField(max_length=60)


    @property
    def valor_a_receber(self):
        return self.comissao_venda.porcentagem * self.valor_venda


    def __str__(self):
        return str(self.vendedor)

and my problem is when I try to delete Comissao object I get this error:

FOREIGN KEY constraint failed

I´ve been hours stuck in this error, hope can someone help me...XD


Solution

  • This is due to the DO_NOTHING: ForeignKeys are enforced at the database level: that means that a commissao_venda needs to refer to a valid Comissao, but if you remove the Commisao, then that is no longer the case, hence the database rejects this. Or, as is documented:

    Take no action. If your database backend enforces referential integrity, this will cause an IntegrityError unless you manually add an SQL ON DELETE constraint to the database field.

    Often DO_NOTHING is not a good idea anyway. The question is what do you want to do with the Venda in case the Comissao it refers to is removed? Two popular options are:

    1. CASCADE, in that case the Venda(s) that refer to that Comissao are removed as well. This can trigger other removals, and thus a single Comissao can eventually trigger removing a lot of records from several tables; or

    2. SET_NULL, you will have to make your field NULLable, by setting null=True [Django-doc]. In that case the commissao_venda will be set to NULL/None. The field thus then looks like:

      comissao_venda = models.ForeignKey(Comissao, null=True, on_delete=models.SET_NULL)

    Other options are PROTECT, RESTRICT, SET_DEFAULT, and SET(…). It of course all depends on what you want to happen in that case.