'Integrity Error on DRF on fixture teardown
I have these 2 models in Django:
class Invoice(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
owner = models.ForeignKey(to="User", on_delete=models.CASCADE)
client = models.ForeignKey(to=Client, on_delete=models.CASCADE)
project = models.ForeignKey(to=Project, on_delete=models.CASCADE)
work_sessions = models.ManyToManyField (WorkSession)
fixed_travels = models.ManyToManyField(FixedTravel)
hourly_travels = models.ManyToManyField(HourlyTravel)
class WorkSession(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
start_timestamp = models.IntegerField(editable=True, null=False, blank=False)
end_timestamp = models.IntegerField(editable=True, null=False, blank=False)
project = models.ForeignKey(to=Project, on_delete=models.CASCADE)
owner = models.ForeignKey(
to="User", related_name="work_sessions", on_delete=models.CASCADE
)
I'm in the middle of an APITestCase in Django Rest Framework where I create 2 work sessions and one invoice and assign those sessions to the invoice
Now on the fixture teardown, this exception gets thrown
raise IntegrityError(
django.db.utils.IntegrityError: The row in table 'drscm_invoice_work_sessions' with primary key '1' has an invalid foreign key: drscm_invoice_work_sessions.invoice_id contains a value '13ba348db35746c1b7f56884efc6249a' that does not have a corresponding value in drscm_invoice.id.
What I want is for WorkSession to exist even though an Invoice gets deleted And it's not a ManyToOne relationship that I'm looking for :/
What am I doing wrong here ?
EDIT
I've tried to update it to use a through model like this:
class Invoice(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
owner = models.ForeignKey(to="User", on_delete=models.CASCADE)
client = models.ForeignKey(to=Client, on_delete=models.CASCADE)
project = models.ForeignKey(to=Project, on_delete=models.CASCADE)
work_sessions = models.ManyToManyField(
WorkSession,
through="InvoiceWorkSession",
through_fields=("invoice", "work_session"),
blank=True,
)
fixed_travels = models.ManyToManyField(
FixedTravel,
through="InvoiceWorkSession",
through_fields=("invoice", "fixed_travel"),
blank=True,
)
hourly_travels = models.ManyToManyField(
HourlyTravel,
through="InvoiceWorkSession",
through_fields=("invoice", "hourly_travel"),
blank=True,
)
def __str__(self):
return f"{self.id}"
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.client = self.project.client
self.owner = self.project.client.owner
super(Invoice, self).save(
force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields,
)
class InvoiceWorkSession(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, null=True)
work_session = models.ForeignKey(WorkSession, on_delete=models.CASCADE, null=True)
fixed_travel = models.ForeignKey(FixedTravel, on_delete=models.CASCADE, null=True)
hourly_travel = models.ForeignKey(HourlyTravel, on_delete=models.CASCADE, null=True)
and the issue still persists :/
Solution 1:[1]
If a work session is only to be linked with one invoice only modify your models as below
class Invoice(models.Model):
....
work_sessions = models.OneToOne(to=WorkSession, on_delete=models.SET_NULL, null=True, blank=True, related_name="inv_workssessions")
or to attach multiple invoices to worksession use ForeignKey relationship similary.
on_delete=models.CASCADE deletes the all the related objects when the parent object is deleted. on_delete=models.SET_NULL will just remove the foreign key relationship and preserve the row.
You can also check other available option here in official documentation.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Sukhpreet Singh |
