Opened 3 hours ago
Last modified 35 minutes ago
#37238 assigned Bug
6.1: save() falls back to python default for primary key that should come from related instance instead — at Version 2
| Reported by: | Jacob Walls | Owned by: | Jacob Walls |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.1 |
| Severity: | Release blocker | Keywords: | |
| Cc: | Mariusz Felisiak | Triage Stage: | Unreviewed |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
When saving an object whose primary key is a OneToOneField, and when that value is meant to come from an unsaved related object, and when that related object uses db_default, a2348c85fc6c20087935c74cd99340dd4ef2dcdc has the unintentional effect of falling back to the field's default instead of getting it from the related object once saved. EDIT: before 6.1, the fallback was to the related object's db_default expression, which isn't quite right either, so my current proposal is to just match the 6.0 behavior and then bounce the rest to a follow-up issue.
To demonstrate, adjust a test being drafted in this other PR (where the bulk_create() case was considered and handled) to use save() instead:
Passes before a2348c85fc6c20087935c74cd99340dd4ef2dcdc on SQLite. Other databases have other behaviors, like raising integrity errors, so we might need some test skips here. This should be rewritten to use Now() instead of a constant value; I found the constant value was easier to debug.
-
tests/bulk_create/models.py
diff --git a/tests/bulk_create/models.py b/tests/bulk_create/models.py index bc9beba990..34ea0bf3f8 100644
a b class DbDefaultPrimaryKey(models.Model): 157 157 158 158 class Meta: 159 159 required_db_features = {"supports_expression_defaults"} 160 161 162 class IntegerDbDefaultPrimaryKey(models.Model): 163 id = models.IntegerField(primary_key=True, db_default=42) 164 165 class Meta: 166 required_db_features = {"supports_expression_defaults"} 167 168 169 class RelatedToDbDefaultPrimaryKey(models.Model): 170 related = models.OneToOneField( 171 IntegerDbDefaultPrimaryKey, 172 on_delete=models.CASCADE, 173 primary_key=True, 174 default=1, 175 ) 176 177 class Meta: 178 required_db_features = {"supports_expression_defaults"} -
tests/bulk_create/tests.py
diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py index 397fcb9186..2692d62fb1 100644
a b from .models import ( 27 27 DbDefaultModel, 28 28 DbDefaultPrimaryKey, 29 29 FieldsWithDbColumns, 30 IntegerDbDefaultPrimaryKey, 30 31 NoFields, 31 32 NullableFields, 32 33 Pizzeria, … … from .models import ( 35 36 ProxyMultiProxyCountry, 36 37 ProxyProxyCountry, 37 38 RelatedModel, 39 RelatedToDbDefaultPrimaryKey, 38 40 Restaurant, 39 41 SmallAutoFieldModel, 40 42 State, … … class BulkCreateTests(TestCase): 439 441 child = NullableFields.objects.get(integer_field=88) 440 442 self.assertEqual(child.auto_field, parent) 441 443 444 @skipUnlessDBFeature( 445 "can_return_columns_from_insert", "supports_expression_defaults" 446 ) 447 def test_pk_from_related_instance_saved_after_init_with_defaults(self): 448 # Ensure that the related field's Python default references a 449 # different valid object. 450 IntegerDbDefaultPrimaryKey.objects.create(pk=1) 451 related_object = IntegerDbDefaultPrimaryKey() 452 obj = RelatedToDbDefaultPrimaryKey(related=related_object) 453 related_object.save() 454 obj.save() 455 self.assertEqual(obj.pk, related_object.pk) 456 442 457 def test_unsaved_parent(self): 443 458 parent = NoFields() 444 459 msg = (
====================================================================== FAIL: test_pk_from_related_instance_saved_after_init_with_defaults (bulk_create.tests.BulkCreateTests.test_pk_from_related_instance_saved_after_init_with_defaults) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/jwalls/django/tests/bulk_create/tests.py", line 455, in test_pk_from_related_instance_saved_after_init_with_defaults self.assertEqual(obj.pk, related_object.pk) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError: 1 != 42 ---------------------------------------------------------------------- Ran 1 test in 0.007s FAILED (failures=1)
Change History (2)
comment:1 by , 2 hours ago
| Description: | modified (diff) |
|---|---|
| Summary: | 6.1: save() falls back to db_default for primary key that should come from related instance instead → 6.1: save() falls back to python default for primary key that should come from related instance instead |
comment:2 by , 107 minutes ago
| Description: | modified (diff) |
|---|
Ah, in no recent versions does the primary key get inserted with the value from the related object. (It comes from the related object's db_default expression, which can be a separate non-release-blocker ticket.) But it at least shouldn't start coming from the python default in 6.1, I gather.