#36064: save() behavior for new model instance with default primary key does not
apply to CompositePrimaryKey
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: dev | Severity: Release
| blocker
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Based on the [
https://docs.djangoproject.com/en/dev/ref/models/instances
/#how-django-knows-to-update-vs-insert description] of how `save()` is
different than `update_or_create()` if the model's primary key has a
default, i.e. that only an INSERT is attempted if the pk is not set by the
user, I would expect models with a CompositePrimaryKey to behave as if
they "have a default" if all of their composed fields have a default, or
else for this to be called out in the doc.
This test shows this is not the case. The first test showing 2 queries
instead of 1 is not such a serious problem, but the second test not
raising IntegrityError seems like it could bite a user who was expecting
to catch IntegrityError and do a custom update (based on how other models
behave since Django 3.0 and #29260).
{{{#!diff
diff --git a/tests/composite_pk/models/tenant.py
b/tests/composite_pk/models/tenant.py
index ac0b3d9715..2273908031 100644
--- a/tests/composite_pk/models/tenant.py
+++ b/tests/composite_pk/models/tenant.py
@@ -1,3 +1,4 @@
+import uuid
from django.db import models
@@ -46,5 +47,5 @@ class Comment(models.Model):
class Post(models.Model):
pk = models.CompositePrimaryKey("tenant_id", "id")
- tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
- id = models.UUIDField()
+ tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE,
default=1)
+ id = models.UUIDField(default=uuid.uuid4)
diff --git a/tests/composite_pk/test_create.py
b/tests/composite_pk/test_create.py
index 7c9925b946..af7ceb7df2 100644
--- a/tests/composite_pk/test_create.py
+++ b/tests/composite_pk/test_create.py
@@ -1,6 +1,7 @@
+from django.db import IntegrityError
from django.test import TestCase
-from .models import Tenant, User
+from .models import Post, Tenant, User
class CompositePKCreateTests(TestCase):
@@ -14,6 +15,16 @@ class CompositePKCreateTests(TestCase):
id=1,
email="
user...@example.com",
)
+
cls.post = Post.objects.create()
+
+ def test_save_default_pk_not_set(self):
+ with self.assertNumQueries(1):
+ Post().save()
+
+ def test_save_default_pk_set(self):
+ with self.assertRaises(IntegrityError):
+ Post(tenant_id=1, id=
self.post.id).save()
+
def test_create_user(self):
test_cases = (
}}}
--
Ticket URL: <
https://code.djangoproject.com/ticket/36064>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.