mirror of
https://github.com/django/django.git
synced 2025-11-07 07:15:35 +00:00
Fixed #31700 -- Made makemigrations command display meaningful symbols for each operation.
This commit is contained in:
committed by
Mariusz Felisiak
parent
c7e986fc9f
commit
27a3eee721
@@ -5,12 +5,13 @@ from django.contrib.postgres.signals import (
|
||||
)
|
||||
from django.db import NotSupportedError, router
|
||||
from django.db.migrations import AddConstraint, AddIndex, RemoveIndex
|
||||
from django.db.migrations.operations.base import Operation
|
||||
from django.db.migrations.operations.base import Operation, OperationCategory
|
||||
from django.db.models.constraints import CheckConstraint
|
||||
|
||||
|
||||
class CreateExtension(Operation):
|
||||
reversible = True
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@@ -120,6 +121,7 @@ class AddIndexConcurrently(NotInTransactionMixin, AddIndex):
|
||||
"""Create an index using PostgreSQL's CREATE INDEX CONCURRENTLY syntax."""
|
||||
|
||||
atomic = False
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def describe(self):
|
||||
return "Concurrently create index %s on field(s) %s of model %s" % (
|
||||
@@ -145,6 +147,7 @@ class RemoveIndexConcurrently(NotInTransactionMixin, RemoveIndex):
|
||||
"""Remove an index using PostgreSQL's DROP INDEX CONCURRENTLY syntax."""
|
||||
|
||||
atomic = False
|
||||
category = OperationCategory.REMOVAL
|
||||
|
||||
def describe(self):
|
||||
return "Concurrently remove index %s from %s" % (self.name, self.model_name)
|
||||
@@ -213,6 +216,8 @@ class CollationOperation(Operation):
|
||||
class CreateCollation(CollationOperation):
|
||||
"""Create a collation."""
|
||||
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label
|
||||
@@ -236,6 +241,8 @@ class CreateCollation(CollationOperation):
|
||||
class RemoveCollation(CollationOperation):
|
||||
"""Remove a collation."""
|
||||
|
||||
category = OperationCategory.REMOVAL
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label
|
||||
@@ -262,6 +269,8 @@ class AddConstraintNotValid(AddConstraint):
|
||||
NOT VALID syntax.
|
||||
"""
|
||||
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def __init__(self, model_name, constraint):
|
||||
if not isinstance(constraint, CheckConstraint):
|
||||
raise TypeError(
|
||||
@@ -293,6 +302,8 @@ class AddConstraintNotValid(AddConstraint):
|
||||
class ValidateConstraint(Operation):
|
||||
"""Validate a table NOT VALID constraint."""
|
||||
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def __init__(self, model_name, name):
|
||||
self.model_name = model_name
|
||||
self.name = name
|
||||
|
||||
@@ -348,7 +348,7 @@ class Command(BaseCommand):
|
||||
migration_string = self.get_relative_path(writer.path)
|
||||
self.log(" %s\n" % self.style.MIGRATE_LABEL(migration_string))
|
||||
for operation in migration.operations:
|
||||
self.log(" - %s" % operation.describe())
|
||||
self.log(" %s" % operation.formatted_description())
|
||||
if self.scriptable:
|
||||
self.stdout.write(migration_string)
|
||||
if not self.dry_run:
|
||||
@@ -456,7 +456,7 @@ class Command(BaseCommand):
|
||||
for migration in merge_migrations:
|
||||
self.log(self.style.MIGRATE_LABEL(" Branch %s" % migration.name))
|
||||
for operation in migration.merged_operations:
|
||||
self.log(" - %s" % operation.describe())
|
||||
self.log(" %s" % operation.formatted_description())
|
||||
if questioner.ask_merge(app_label):
|
||||
# If they still want to merge it, then write out an empty
|
||||
# file depending on the migrations needing merging.
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import enum
|
||||
|
||||
from django.db import router
|
||||
|
||||
|
||||
class OperationCategory(str, enum.Enum):
|
||||
ADDITION = "+"
|
||||
REMOVAL = "-"
|
||||
ALTERATION = "~"
|
||||
PYTHON = "p"
|
||||
SQL = "s"
|
||||
MIXED = "?"
|
||||
|
||||
|
||||
class Operation:
|
||||
"""
|
||||
Base class for migration operations.
|
||||
@@ -33,6 +44,8 @@ class Operation:
|
||||
|
||||
serialization_expand_args = []
|
||||
|
||||
category = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# We capture the arguments to make returning them trivial
|
||||
self = object.__new__(cls)
|
||||
@@ -85,6 +98,13 @@ class Operation:
|
||||
"""
|
||||
return "%s: %s" % (self.__class__.__name__, self._constructor_args)
|
||||
|
||||
def formatted_description(self):
|
||||
"""Output a description prefixed by a category symbol."""
|
||||
description = self.describe()
|
||||
if self.category is None:
|
||||
return f"{OperationCategory.MIXED.value} {description}"
|
||||
return f"{self.category.value} {description}"
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@ from django.db.migrations.utils import field_references
|
||||
from django.db.models import NOT_PROVIDED
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from .base import Operation
|
||||
from .base import Operation, OperationCategory
|
||||
|
||||
|
||||
class FieldOperation(Operation):
|
||||
@@ -75,6 +75,8 @@ class FieldOperation(Operation):
|
||||
class AddField(FieldOperation):
|
||||
"""Add a field to a model."""
|
||||
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def __init__(self, model_name, name, field, preserve_default=True):
|
||||
self.preserve_default = preserve_default
|
||||
super().__init__(model_name, name, field)
|
||||
@@ -154,6 +156,8 @@ class AddField(FieldOperation):
|
||||
class RemoveField(FieldOperation):
|
||||
"""Remove a field from a model."""
|
||||
|
||||
category = OperationCategory.REMOVAL
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
@@ -201,6 +205,8 @@ class AlterField(FieldOperation):
|
||||
new field.
|
||||
"""
|
||||
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def __init__(self, model_name, name, field, preserve_default=True):
|
||||
self.preserve_default = preserve_default
|
||||
super().__init__(model_name, name, field)
|
||||
@@ -270,6 +276,8 @@ class AlterField(FieldOperation):
|
||||
class RenameField(FieldOperation):
|
||||
"""Rename a field on the model. Might affect db_column too."""
|
||||
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def __init__(self, model_name, old_name, new_name):
|
||||
self.old_name = old_name
|
||||
self.new_name = new_name
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.db import models
|
||||
from django.db.migrations.operations.base import Operation
|
||||
from django.db.migrations.operations.base import Operation, OperationCategory
|
||||
from django.db.migrations.state import ModelState
|
||||
from django.db.migrations.utils import field_references, resolve_relation
|
||||
from django.db.models.options import normalize_together
|
||||
@@ -41,6 +41,7 @@ class ModelOperation(Operation):
|
||||
class CreateModel(ModelOperation):
|
||||
"""Create a model's table."""
|
||||
|
||||
category = OperationCategory.ADDITION
|
||||
serialization_expand_args = ["fields", "options", "managers"]
|
||||
|
||||
def __init__(self, name, fields, options=None, bases=None, managers=None):
|
||||
@@ -347,6 +348,8 @@ class CreateModel(ModelOperation):
|
||||
class DeleteModel(ModelOperation):
|
||||
"""Drop a model's table."""
|
||||
|
||||
category = OperationCategory.REMOVAL
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
@@ -382,6 +385,8 @@ class DeleteModel(ModelOperation):
|
||||
class RenameModel(ModelOperation):
|
||||
"""Rename a model."""
|
||||
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def __init__(self, old_name, new_name):
|
||||
self.old_name = old_name
|
||||
self.new_name = new_name
|
||||
@@ -499,6 +504,8 @@ class RenameModel(ModelOperation):
|
||||
|
||||
|
||||
class ModelOptionOperation(ModelOperation):
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if (
|
||||
isinstance(operation, (self.__class__, DeleteModel))
|
||||
@@ -849,6 +856,8 @@ class IndexOperation(Operation):
|
||||
class AddIndex(IndexOperation):
|
||||
"""Add an index on a model."""
|
||||
|
||||
category = OperationCategory.ADDITION
|
||||
|
||||
def __init__(self, model_name, index):
|
||||
self.model_name = model_name
|
||||
if not index.name:
|
||||
@@ -911,6 +920,8 @@ class AddIndex(IndexOperation):
|
||||
class RemoveIndex(IndexOperation):
|
||||
"""Remove an index from a model."""
|
||||
|
||||
category = OperationCategory.REMOVAL
|
||||
|
||||
def __init__(self, model_name, name):
|
||||
self.model_name = model_name
|
||||
self.name = name
|
||||
@@ -954,6 +965,8 @@ class RemoveIndex(IndexOperation):
|
||||
class RenameIndex(IndexOperation):
|
||||
"""Rename an index."""
|
||||
|
||||
category = OperationCategory.ALTERATION
|
||||
|
||||
def __init__(self, model_name, new_name, old_name=None, old_fields=None):
|
||||
if not old_name and not old_fields:
|
||||
raise ValueError(
|
||||
@@ -1104,6 +1117,7 @@ class RenameIndex(IndexOperation):
|
||||
|
||||
|
||||
class AddConstraint(IndexOperation):
|
||||
category = OperationCategory.ADDITION
|
||||
option_name = "constraints"
|
||||
|
||||
def __init__(self, model_name, constraint):
|
||||
@@ -1154,6 +1168,7 @@ class AddConstraint(IndexOperation):
|
||||
|
||||
|
||||
class RemoveConstraint(IndexOperation):
|
||||
category = OperationCategory.REMOVAL
|
||||
option_name = "constraints"
|
||||
|
||||
def __init__(self, model_name, name):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.db import router
|
||||
|
||||
from .base import Operation
|
||||
from .base import Operation, OperationCategory
|
||||
|
||||
|
||||
class SeparateDatabaseAndState(Operation):
|
||||
@@ -11,6 +11,7 @@ class SeparateDatabaseAndState(Operation):
|
||||
that affect the state or not the database, or so on.
|
||||
"""
|
||||
|
||||
category = OperationCategory.MIXED
|
||||
serialization_expand_args = ["database_operations", "state_operations"]
|
||||
|
||||
def __init__(self, database_operations=None, state_operations=None):
|
||||
@@ -68,6 +69,7 @@ class RunSQL(Operation):
|
||||
by this SQL change, in case it's custom column/table creation/deletion.
|
||||
"""
|
||||
|
||||
category = OperationCategory.SQL
|
||||
noop = ""
|
||||
|
||||
def __init__(
|
||||
@@ -138,6 +140,7 @@ class RunPython(Operation):
|
||||
Run Python code in a context suitable for doing versioned ORM operations.
|
||||
"""
|
||||
|
||||
category = OperationCategory.PYTHON
|
||||
reduces_to_sql = False
|
||||
|
||||
def __init__(
|
||||
|
||||
Reference in New Issue
Block a user