1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

Refs #36064 -- Added Model.has_db_default() to encapsulate NOT_PROVIDED checks.

This avoids many awkward checks against NOT_PROVIDED and provides symmetry
with Field.has_default() which is also the reason why it wasn't made a
property.
This commit is contained in:
Simon Charette 2024-12-09 22:14:59 -05:00 committed by Sarah Boyce
parent 0fb51ec5a0
commit 9fa4d07ce0
6 changed files with 27 additions and 40 deletions

View File

@ -13,7 +13,7 @@ from django.db.backends.ddl_references import (
Table, Table,
) )
from django.db.backends.utils import names_digest, split_identifier, truncate_name from django.db.backends.utils import names_digest, split_identifier, truncate_name
from django.db.models import NOT_PROVIDED, Deferrable, Index from django.db.models import Deferrable, Index
from django.db.models.fields.composite import CompositePrimaryKey from django.db.models.fields.composite import CompositePrimaryKey
from django.db.models.sql import Query from django.db.models.sql import Query
from django.db.transaction import TransactionManagementError, atomic from django.db.transaction import TransactionManagementError, atomic
@ -318,7 +318,7 @@ class BaseDatabaseSchemaEditor:
# Work out nullability. # Work out nullability.
null = field.null null = field.null
# Add database default. # Add database default.
if field.db_default is not NOT_PROVIDED: if field.has_db_default():
default_sql, default_params = self.db_default_sql(field) default_sql, default_params = self.db_default_sql(field)
yield f"DEFAULT {default_sql}" yield f"DEFAULT {default_sql}"
params.extend(default_params) params.extend(default_params)
@ -775,7 +775,7 @@ class BaseDatabaseSchemaEditor:
self.execute(sql, params or None) self.execute(sql, params or None)
# Drop the default if we need to # Drop the default if we need to
if ( if (
field.db_default is NOT_PROVIDED not field.has_db_default()
and not self.skip_default_on_alter(field) and not self.skip_default_on_alter(field)
and self.effective_default(field) is not None and self.effective_default(field) is not None
): ):
@ -1108,15 +1108,15 @@ class BaseDatabaseSchemaEditor:
actions.append(fragment) actions.append(fragment)
post_actions.extend(other_actions) post_actions.extend(other_actions)
if new_field.db_default is not NOT_PROVIDED: if new_field.has_db_default():
if ( if (
old_field.db_default is NOT_PROVIDED not old_field.has_db_default()
or new_field.db_default != old_field.db_default or new_field.db_default != old_field.db_default
): ):
actions.append( actions.append(
self._alter_column_database_default_sql(model, old_field, new_field) self._alter_column_database_default_sql(model, old_field, new_field)
) )
elif old_field.db_default is not NOT_PROVIDED: elif old_field.has_db_default():
actions.append( actions.append(
self._alter_column_database_default_sql( self._alter_column_database_default_sql(
model, old_field, new_field, drop=True model, old_field, new_field, drop=True
@ -1130,11 +1130,7 @@ class BaseDatabaseSchemaEditor:
# 4. Drop the default again. # 4. Drop the default again.
# Default change? # Default change?
needs_database_default = False needs_database_default = False
if ( if old_field.null and not new_field.null and not new_field.has_db_default():
old_field.null
and not new_field.null
and new_field.db_default is NOT_PROVIDED
):
old_default = self.effective_default(old_field) old_default = self.effective_default(old_field)
new_default = self.effective_default(new_field) new_default = self.effective_default(new_field)
if ( if (
@ -1153,7 +1149,7 @@ class BaseDatabaseSchemaEditor:
null_actions.append(fragment) null_actions.append(fragment)
# Only if we have a default and there is a change from NULL to NOT NULL # Only if we have a default and there is a change from NULL to NOT NULL
four_way_default_alteration = ( four_way_default_alteration = (
new_field.has_default() or new_field.db_default is not NOT_PROVIDED new_field.has_default() or new_field.has_db_default()
) and (old_field.null and not new_field.null) ) and (old_field.null and not new_field.null)
if actions or null_actions: if actions or null_actions:
if not four_way_default_alteration: if not four_way_default_alteration:
@ -1175,7 +1171,7 @@ class BaseDatabaseSchemaEditor:
params, params,
) )
if four_way_default_alteration: if four_way_default_alteration:
if new_field.db_default is NOT_PROVIDED: if not new_field.has_db_default():
default_sql = "%s" default_sql = "%s"
params = [new_default] params = [new_default]
else: else:

View File

@ -222,7 +222,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
Keep the NULL and DEFAULT properties of the old field. If it has Keep the NULL and DEFAULT properties of the old field. If it has
changed, it will be handled separately. changed, it will be handled separately.
""" """
if field.db_default is not NOT_PROVIDED: if field.has_db_default():
default_sql, params = self.db_default_sql(field) default_sql, params = self.db_default_sql(field)
default_sql %= tuple(self.quote_value(p) for p in params) default_sql %= tuple(self.quote_value(p) for p in params)
new_type += f" DEFAULT {default_sql}" new_type += f" DEFAULT {default_sql}"
@ -266,7 +266,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
return f" COMMENT {comment_sql}" return f" COMMENT {comment_sql}"
def _alter_column_null_sql(self, model, old_field, new_field): def _alter_column_null_sql(self, model, old_field, new_field):
if new_field.db_default is NOT_PROVIDED: if not new_field.has_db_default():
return super()._alter_column_null_sql(model, old_field, new_field) return super()._alter_column_null_sql(model, old_field, new_field)
new_db_params = new_field.db_parameters(connection=self.connection) new_db_params = new_field.db_parameters(connection=self.connection)

View File

@ -6,7 +6,7 @@ from django.db import NotSupportedError
from django.db.backends.base.schema import BaseDatabaseSchemaEditor from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.backends.ddl_references import Statement from django.db.backends.ddl_references import Statement
from django.db.backends.utils import strip_quotes from django.db.backends.utils import strip_quotes
from django.db.models import NOT_PROVIDED, CompositePrimaryKey, UniqueConstraint from django.db.models import CompositePrimaryKey, UniqueConstraint
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
@ -144,7 +144,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
body[create_field.name] = create_field body[create_field.name] = create_field
# Choose a default and insert it into the copy map # Choose a default and insert it into the copy map
if ( if (
create_field.db_default is NOT_PROVIDED not create_field.has_db_default()
and not (create_field.many_to_many or create_field.generated) and not (create_field.many_to_many or create_field.generated)
and create_field.concrete and create_field.concrete
): ):
@ -161,7 +161,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
if new_field.generated: if new_field.generated:
continue continue
if old_field.null and not new_field.null: if old_field.null and not new_field.null:
if new_field.db_default is NOT_PROVIDED: if not new_field.has_db_default():
default = self.prepare_default(self.effective_default(new_field)) default = self.prepare_default(self.effective_default(new_field))
else: else:
default, _ = self.db_default_sql(new_field) default, _ = self.db_default_sql(new_field)
@ -321,10 +321,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
or self.effective_default(field) is not None or self.effective_default(field) is not None
# Fields with non-constant defaults cannot by handled by ALTER # Fields with non-constant defaults cannot by handled by ALTER
# TABLE ADD COLUMN statement. # TABLE ADD COLUMN statement.
or ( or (field.has_db_default() and not isinstance(field.db_default, Value))
field.db_default is not NOT_PROVIDED
and not isinstance(field.db_default, Value)
)
): ):
self._remake_table(model, create_field=field) self._remake_table(model, create_field=field)
else: else:

View File

@ -1135,7 +1135,7 @@ class MigrationAutodetector:
preserve_default = ( preserve_default = (
field.null field.null
or field.has_default() or field.has_default()
or field.db_default is not models.NOT_PROVIDED or field.has_db_default()
or field.many_to_many or field.many_to_many
or (field.blank and field.empty_strings_allowed) or (field.blank and field.empty_strings_allowed)
or (isinstance(field, time_fields) and field.auto_now) or (isinstance(field, time_fields) and field.auto_now)
@ -1150,11 +1150,7 @@ class MigrationAutodetector:
field.default = self.questioner.ask_not_null_addition( field.default = self.questioner.ask_not_null_addition(
field_name, model_name field_name, model_name
) )
if ( if field.unique and field.has_default() and callable(field.default):
field.unique
and field.default is not models.NOT_PROVIDED
and callable(field.default)
):
self.questioner.ask_unique_callable_default_addition(field_name, model_name) self.questioner.ask_unique_callable_default_addition(field_name, model_name)
self.add_operation( self.add_operation(
app_label, app_label,
@ -1296,7 +1292,7 @@ class MigrationAutodetector:
old_field.null old_field.null
and not new_field.null and not new_field.null
and not new_field.has_default() and not new_field.has_default()
and new_field.db_default is models.NOT_PROVIDED and not new_field.has_db_default()
and not new_field.many_to_many and not new_field.many_to_many
): ):
field = new_field.clone() field = new_field.clone()

View File

@ -1118,10 +1118,7 @@ class Model(AltersData, metaclass=ModelBase):
and not force_insert and not force_insert
and not force_update and not force_update
and self._state.adding and self._state.adding
and ( and (meta.pk.has_default() or meta.pk.has_db_default())
(meta.pk.default and meta.pk.default is not NOT_PROVIDED)
or (meta.pk.db_default and meta.pk.db_default is not NOT_PROVIDED)
)
): ):
force_insert = True force_insert = True
# If possible, try an UPDATE. If that doesn't update anything, do an INSERT. # If possible, try an UPDATE. If that doesn't update anything, do an INSERT.

View File

@ -391,7 +391,7 @@ class Field(RegisterLookupMixin):
from django.db.models.expressions import Value from django.db.models.expressions import Value
if ( if (
self.db_default is NOT_PROVIDED not self.has_db_default()
or ( or (
isinstance(self.db_default, Value) isinstance(self.db_default, Value)
or not hasattr(self.db_default, "resolve_expression") or not hasattr(self.db_default, "resolve_expression")
@ -933,8 +933,7 @@ class Field(RegisterLookupMixin):
def db_returning(self): def db_returning(self):
"""Private API intended only to be used by Django itself.""" """Private API intended only to be used by Django itself."""
return ( return (
self.db_default is not NOT_PROVIDED self.has_db_default() and connection.features.can_return_columns_from_insert
and connection.features.can_return_columns_from_insert
) )
def set_attributes_from_name(self, name): def set_attributes_from_name(self, name):
@ -1016,6 +1015,10 @@ class Field(RegisterLookupMixin):
"""Return a boolean of whether this field has a default value.""" """Return a boolean of whether this field has a default value."""
return self.default is not NOT_PROVIDED return self.default is not NOT_PROVIDED
def has_db_default(self):
"""Return a boolean of whether this field has a db_default value."""
return self.db_default is not NOT_PROVIDED
def get_default(self): def get_default(self):
"""Return the default value for this field.""" """Return the default value for this field."""
return self._get_default() return self._get_default()
@ -1027,7 +1030,7 @@ class Field(RegisterLookupMixin):
return self.default return self.default
return lambda: self.default return lambda: self.default
if self.db_default is not NOT_PROVIDED: if self.has_db_default():
from django.db.models.expressions import DatabaseDefault from django.db.models.expressions import DatabaseDefault
return lambda: DatabaseDefault( return lambda: DatabaseDefault(
@ -1045,9 +1048,7 @@ class Field(RegisterLookupMixin):
@cached_property @cached_property
def _db_default_expression(self): def _db_default_expression(self):
db_default = self.db_default db_default = self.db_default
if db_default is not NOT_PROVIDED and not hasattr( if self.has_db_default() and not hasattr(db_default, "resolve_expression"):
db_default, "resolve_expression"
):
from django.db.models.expressions import Value from django.db.models.expressions import Value
db_default = Value(db_default, self) db_default = Value(db_default, self)