I have the following models in django
class WorkSession(models.Model):
pass
class Invoice(models.Model):
work_sessions = models.ManyToManyField(WorkSession, blank=True)
what I noticed is that when i do the following:
invoice = Invoice()
session = WorkSession(a=a, b=b)
invoiceo.work_sessions.set([session])
The invoice_worksession junction table gets populated with a relation, even though I haven't saved invoice yet. Meaning that the invoices table, there's no row, but in the junction table, there's a row that references an invoice that doesn't exist yet. Is this normal ?
Because this is causing an integrity error on fixture teardown since the invoice doesn't exist and yet, there's a refrence to an invoice id in the junction table
EDIT
The following is a better explanation of what I'm trying to do and the problem itself
Here are my tables
CREATE TABLE "drscm_worksession" (
"id" char(32) NOT NULL,
"start_timestamp" integer NOT NULL,
"end_timestamp" integer NOT NULL,
PRIMARY KEY("id"),
);
CREATE TABLE "drscm_invoice" (
"id" char(32) NOT NULL,
PRIMARY KEY("id"),
);
and the junction table
CREATE TABLE "drscm_invoice_work_sessions" (
"id" integer NOT NULL,
"invoice_id" char(32) NOT NULL,
"worksession_id" char(32) NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT),
FOREIGN KEY("invoice_id") REFERENCES "drscm_invoice"("id") DEFERRABLE INITIALLY DEFERRED,
FOREIGN KEY("worksession_id") REFERENCES "drscm_worksession"("id") DEFERRABLE INITIALLY DEFERRED
);
The objective is to create an invoice in the database with work_sessions via an api call.
The data i would need to send over, using my api client is this:
{work_sessions: [uuid1, uuid2] }
so the code would be
url = "/invoices/"
ws1 = WorkSession().save()
ws2 = WorkSession().save()
data = {'work_sessions': [ws1.id, ws2.id] }
self.client.post(path=url, data=data)
This works PERFECTLY. BUT, I thought, I don't want to have to write these objects manually as they get bigger in the real test. So the approach was to do this:
invoice = Invoice()
invoice.work_sessions.set([ws1, ws2])
data = InvoiceSerializer(instance=invoice).data
self.client.post(path=url, data=data)
This does create the invoice with the according sessions BUT throws an IntegrityError
exception during the teardown
phase of the test
Here's why it throws the exception:
Invoice()
creates an instance of the object and that instance has anid
, but the invoice is NOT in the databaseinvoice.work_sessions.set([ws1, ws2])
creates 2 rows in the drscm_invoice_work_sessions table (junction table), and theinvoice_id
column takes the id of the NOT CREATEDinvoice
instance. ( Which is the bug here)- During teardown, it tries do delete the relations in the junction table --> looks for an invoice with id:
invoice.id
in thedrscm_invoices
table, but it doesn't exit. --> Throws an exception
You need to save the objects first to the database, such that these have a primary key, so: