Fixed #35149 -- Fixed crashes of db_default with unresolvable output field.

Field.db_default accepts either literal Python values or compilables
(as_sql) and wrap the former ones in Value internally.

While 1e38f11 added support for automatic resolving of output fields for
types such as str, int, float, and other unambigous ones it's cannot do
so for all types such as dict or even contrib.postgres and contrib.gis
primitives.

When a literal, non-compilable, value is provided it likely make the
most sense to bind its output field to the field its attached to avoid
forcing the user to provide an explicit `Value(output_field)`.

Thanks David Sanders for the report.
This commit is contained in:
Simon Charette 2024-01-28 12:02:33 -05:00 committed by Mariusz Felisiak
parent fe1cb62f5c
commit e67d7d70fa
6 changed files with 50 additions and 20 deletions

View file

@ -1581,7 +1581,7 @@ class OperationTests(OperationTestBase):
self.assertEqual(len(new_state.models[app_label, "pony"].fields), 6)
field = new_state.models[app_label, "pony"].fields["height"]
self.assertEqual(field.default, models.NOT_PROVIDED)
self.assertEqual(field.db_default, Value(4))
self.assertEqual(field.db_default, 4)
project_state.apps.get_model(app_label, "pony").objects.create(weight=4)
self.assertColumnNotExists(table_name, "height")
# Add field.
@ -1632,7 +1632,7 @@ class OperationTests(OperationTestBase):
self.assertEqual(len(new_state.models[app_label, "pony"].fields), 6)
field = new_state.models[app_label, "pony"].fields["special_char"]
self.assertEqual(field.default, models.NOT_PROVIDED)
self.assertEqual(field.db_default, Value(db_default))
self.assertEqual(field.db_default, db_default)
self.assertColumnNotExists(table_name, "special_char")
with connection.schema_editor() as editor:
operation.database_forwards(
@ -1700,7 +1700,7 @@ class OperationTests(OperationTestBase):
self.assertEqual(len(new_state.models[app_label, "pony"].fields), 6)
field = new_state.models[app_label, "pony"].fields["height"]
self.assertEqual(field.default, 3)
self.assertEqual(field.db_default, Value(4))
self.assertEqual(field.db_default, 4)
pre_pony_pk = (
project_state.apps.get_model(app_label, "pony").objects.create(weight=4).pk
)
@ -2145,7 +2145,7 @@ class OperationTests(OperationTestBase):
old_weight = project_state.models[app_label, "pony"].fields["weight"]
self.assertIs(old_weight.db_default, models.NOT_PROVIDED)
new_weight = new_state.models[app_label, "pony"].fields["weight"]
self.assertEqual(new_weight.db_default, Value(4.5))
self.assertEqual(new_weight.db_default, 4.5)
with self.assertRaises(IntegrityError), transaction.atomic():
project_state.apps.get_model(app_label, "pony").objects.create()
# Alter field.
@ -2187,7 +2187,7 @@ class OperationTests(OperationTestBase):
self.assertIs(old_pink.db_default, models.NOT_PROVIDED)
new_pink = new_state.models[app_label, "pony"].fields["pink"]
self.assertIs(new_pink.default, models.NOT_PROVIDED)
self.assertEqual(new_pink.db_default, Value(4))
self.assertEqual(new_pink.db_default, 4)
pony = project_state.apps.get_model(app_label, "pony").objects.create(weight=1)
self.assertEqual(pony.pink, 3)
# Alter field.
@ -2217,7 +2217,7 @@ class OperationTests(OperationTestBase):
old_green = project_state.models[app_label, "pony"].fields["green"]
self.assertIs(old_green.db_default, models.NOT_PROVIDED)
new_green = new_state.models[app_label, "pony"].fields["green"]
self.assertEqual(new_green.db_default, Value(4))
self.assertEqual(new_green.db_default, 4)
old_pony = project_state.apps.get_model(app_label, "pony").objects.create(
weight=1
)