diff options
| author | Simon Charette <charette.s@gmail.com> | 2024-01-28 12:02:33 -0500 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2024-02-04 14:48:44 +0100 |
| commit | 761946f8e1b6d725f83fa4f3b04ca9750f486009 (patch) | |
| tree | 9dd3f0bc8320d2e5f943ceb271d801ab840cb917 /django | |
| parent | 914eee1a9bee7ae48e6b23ef905ec00bcc241791 (diff) | |
[5.0.x] 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.
Backport of e67d7d70fa10c06aca36b9057f82054eda45269d from main
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/backends/base/schema.py | 7 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 21 |
2 files changed, 16 insertions, 12 deletions
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py index a319b5ecd5..d2c8c65979 100644 --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -412,14 +412,13 @@ class BaseDatabaseSchemaEditor: """Return the sql and params for the field's database default.""" from django.db.models.expressions import Value + db_default = field._db_default_expression sql = ( - self._column_default_sql(field) - if isinstance(field.db_default, Value) - else "(%s)" + self._column_default_sql(field) if isinstance(db_default, Value) else "(%s)" ) query = Query(model=field.model) compiler = query.get_compiler(connection=self.connection) - default_sql, params = compiler.compile(field.db_default) + default_sql, params = compiler.compile(db_default) if self.connection.features.requires_literal_defaults: # Some databases doesn't support parameterized defaults (Oracle, # SQLite). If this is the case, the individual schema backend diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index ce3bebb591..26cb1bc485 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -218,12 +218,6 @@ class Field(RegisterLookupMixin): self.remote_field = rel self.is_relation = self.remote_field is not None self.default = default - if db_default is not NOT_PROVIDED and not hasattr( - db_default, "resolve_expression" - ): - from django.db.models.expressions import Value - - db_default = Value(db_default) self.db_default = db_default self.editable = editable self.serialize = serialize @@ -407,7 +401,7 @@ class Field(RegisterLookupMixin): continue connection = connections[db] - if not getattr(self.db_default, "allowed_default", False) and ( + if not getattr(self._db_default_expression, "allowed_default", False) and ( connection.features.supports_expression_defaults ): msg = f"{self.db_default} cannot be used in db_default." @@ -993,7 +987,7 @@ class Field(RegisterLookupMixin): from django.db.models.expressions import DatabaseDefault if isinstance(value, DatabaseDefault): - return self.db_default + return self._db_default_expression return value def get_prep_value(self, value): @@ -1046,6 +1040,17 @@ class Field(RegisterLookupMixin): return return_None return str # return empty string + @cached_property + def _db_default_expression(self): + db_default = self.db_default + if db_default is not NOT_PROVIDED and not hasattr( + db_default, "resolve_expression" + ): + from django.db.models.expressions import Value + + db_default = Value(db_default, self) + return db_default + def get_choices( self, include_blank=True, |
