Opened 7 years ago
Last modified 8 months ago
#28715 new Cleanup/optimization
Prevent a migration changing DateTimeField(auto_now_add=True) to default=timezone.now from generating SQL — at Version 2
Reported by: | Дилян Палаузов | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Ülgen Sarıkavak | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
A switch from DateTimeField(auto_now_add=True) to DateTimeField(default=django.utils.timezone.new) creates the statements
ALTER TABLE SET DEFAULT '2017-10-16T09:35:52.710695'::timestamp;
ALTER TABLE DROP DEFAULT
which have no effects, apart from locking the whole table twice.
A proposal to recognize, when the effective default-callable doesn't change and skip changing the DEFAULT twice in this case, as well as not generating a migration when this is the only change on a field:
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -199,28 +199,33 @@ class BaseDatabaseSchemaEditor(object): 'requires_literal_defaults must provide a prepare_default() method' ) - def effective_default(self, field): + @staticmethod + def effective_default_before_callable(field): """ - Returns a field's effective database default value + Returns a field's effective database default callable or value """ if field.has_default(): - default = field.get_default() + return field._get_default elif not field.null and field.blank and field.empty_strings_allowed: if field.get_internal_type() == "BinaryField": - default = six.binary_type() + return six.binary_type() else: - default = six.text_type() + return six.text_type() elif getattr(field, 'auto_now', False) or getattr(field, 'auto_now_add', False): default = datetime.now() internal_type = field.get_internal_type() if internal_type == 'DateField': - default = default.date + return default.date elif internal_type == 'TimeField': - default = default.time + return default.time elif internal_type == 'DateTimeField': - default = timezone.now - else: - default = None + return timezone.now + + def effective_default(self, field): + """ + Returns a field's effective database default value + """ + default = BaseDatabaseSchemaEditor.effective_default_before_callable(field) # If it's a callable, call it if callable(default): default = default() @@ -615,6 +620,7 @@ class BaseDatabaseSchemaEditor(object): old_default != new_default and new_default is not None and not self.skip_default(new_field) + and BaseDatabaseSchemaEditor.effective_default_before_callable(old_field) != BaseDatabaseSchemaEdit ) if needs_database_default: if self.connection.features.requires_literal_defaults: diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1232,7 +1232,7 @@ class DateField(DateTimeCheckMixin, Field): if self.auto_now: kwargs['auto_now'] = True if self.auto_now_add: - kwargs['auto_now_add'] = True + kwargs['default'] = timezone.now if self.auto_now or self.auto_now_add: del kwargs['editable'] del kwargs['blank']
Change History (2)
comment:1 by , 7 years ago
Summary: | Migration DateTimeField(auto_now_add=True -> default=django.utils.timezone.new) → Prevent a migration changing DateTimeField(auto_now_add=True) to default=timezone.now from generating SQL |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 7 years ago
Description: | modified (diff) |
---|