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 :/
If a work session is only to be linked with one invoice only modify your models as below
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.