mirror of https://github.com/django/django.git
Fixed #31700 -- Made makemigrations command display meaningful symbols for each operation.
This commit is contained in:
parent
c7e986fc9f
commit
27a3eee721
|
@ -5,12 +5,13 @@ from django.contrib.postgres.signals import (
|
||||||
)
|
)
|
||||||
from django.db import NotSupportedError, router
|
from django.db import NotSupportedError, router
|
||||||
from django.db.migrations import AddConstraint, AddIndex, RemoveIndex
|
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
|
from django.db.models.constraints import CheckConstraint
|
||||||
|
|
||||||
|
|
||||||
class CreateExtension(Operation):
|
class CreateExtension(Operation):
|
||||||
reversible = True
|
reversible = True
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -120,6 +121,7 @@ class AddIndexConcurrently(NotInTransactionMixin, AddIndex):
|
||||||
"""Create an index using PostgreSQL's CREATE INDEX CONCURRENTLY syntax."""
|
"""Create an index using PostgreSQL's CREATE INDEX CONCURRENTLY syntax."""
|
||||||
|
|
||||||
atomic = False
|
atomic = False
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return "Concurrently create index %s on field(s) %s of model %s" % (
|
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."""
|
"""Remove an index using PostgreSQL's DROP INDEX CONCURRENTLY syntax."""
|
||||||
|
|
||||||
atomic = False
|
atomic = False
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return "Concurrently remove index %s from %s" % (self.name, self.model_name)
|
return "Concurrently remove index %s from %s" % (self.name, self.model_name)
|
||||||
|
@ -213,6 +216,8 @@ class CollationOperation(Operation):
|
||||||
class CreateCollation(CollationOperation):
|
class CreateCollation(CollationOperation):
|
||||||
"""Create a collation."""
|
"""Create a collation."""
|
||||||
|
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
||||||
schema_editor.connection.alias, app_label
|
schema_editor.connection.alias, app_label
|
||||||
|
@ -236,6 +241,8 @@ class CreateCollation(CollationOperation):
|
||||||
class RemoveCollation(CollationOperation):
|
class RemoveCollation(CollationOperation):
|
||||||
"""Remove a collation."""
|
"""Remove a collation."""
|
||||||
|
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
||||||
schema_editor.connection.alias, app_label
|
schema_editor.connection.alias, app_label
|
||||||
|
@ -262,6 +269,8 @@ class AddConstraintNotValid(AddConstraint):
|
||||||
NOT VALID syntax.
|
NOT VALID syntax.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, model_name, constraint):
|
def __init__(self, model_name, constraint):
|
||||||
if not isinstance(constraint, CheckConstraint):
|
if not isinstance(constraint, CheckConstraint):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
|
@ -293,6 +302,8 @@ class AddConstraintNotValid(AddConstraint):
|
||||||
class ValidateConstraint(Operation):
|
class ValidateConstraint(Operation):
|
||||||
"""Validate a table NOT VALID constraint."""
|
"""Validate a table NOT VALID constraint."""
|
||||||
|
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def __init__(self, model_name, name):
|
def __init__(self, model_name, name):
|
||||||
self.model_name = model_name
|
self.model_name = model_name
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
|
@ -348,7 +348,7 @@ class Command(BaseCommand):
|
||||||
migration_string = self.get_relative_path(writer.path)
|
migration_string = self.get_relative_path(writer.path)
|
||||||
self.log(" %s\n" % self.style.MIGRATE_LABEL(migration_string))
|
self.log(" %s\n" % self.style.MIGRATE_LABEL(migration_string))
|
||||||
for operation in migration.operations:
|
for operation in migration.operations:
|
||||||
self.log(" - %s" % operation.describe())
|
self.log(" %s" % operation.formatted_description())
|
||||||
if self.scriptable:
|
if self.scriptable:
|
||||||
self.stdout.write(migration_string)
|
self.stdout.write(migration_string)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
|
@ -456,7 +456,7 @@ class Command(BaseCommand):
|
||||||
for migration in merge_migrations:
|
for migration in merge_migrations:
|
||||||
self.log(self.style.MIGRATE_LABEL(" Branch %s" % migration.name))
|
self.log(self.style.MIGRATE_LABEL(" Branch %s" % migration.name))
|
||||||
for operation in migration.merged_operations:
|
for operation in migration.merged_operations:
|
||||||
self.log(" - %s" % operation.describe())
|
self.log(" %s" % operation.formatted_description())
|
||||||
if questioner.ask_merge(app_label):
|
if questioner.ask_merge(app_label):
|
||||||
# If they still want to merge it, then write out an empty
|
# If they still want to merge it, then write out an empty
|
||||||
# file depending on the migrations needing merging.
|
# file depending on the migrations needing merging.
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
|
import enum
|
||||||
|
|
||||||
from django.db import router
|
from django.db import router
|
||||||
|
|
||||||
|
|
||||||
|
class OperationCategory(str, enum.Enum):
|
||||||
|
ADDITION = "+"
|
||||||
|
REMOVAL = "-"
|
||||||
|
ALTERATION = "~"
|
||||||
|
PYTHON = "p"
|
||||||
|
SQL = "s"
|
||||||
|
MIXED = "?"
|
||||||
|
|
||||||
|
|
||||||
class Operation:
|
class Operation:
|
||||||
"""
|
"""
|
||||||
Base class for migration operations.
|
Base class for migration operations.
|
||||||
|
@ -33,6 +44,8 @@ class Operation:
|
||||||
|
|
||||||
serialization_expand_args = []
|
serialization_expand_args = []
|
||||||
|
|
||||||
|
category = None
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
# We capture the arguments to make returning them trivial
|
# We capture the arguments to make returning them trivial
|
||||||
self = object.__new__(cls)
|
self = object.__new__(cls)
|
||||||
|
@ -85,6 +98,13 @@ class Operation:
|
||||||
"""
|
"""
|
||||||
return "%s: %s" % (self.__class__.__name__, self._constructor_args)
|
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
|
@property
|
||||||
def migration_name_fragment(self):
|
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.db.models import NOT_PROVIDED
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from .base import Operation
|
from .base import Operation, OperationCategory
|
||||||
|
|
||||||
|
|
||||||
class FieldOperation(Operation):
|
class FieldOperation(Operation):
|
||||||
|
@ -75,6 +75,8 @@ class FieldOperation(Operation):
|
||||||
class AddField(FieldOperation):
|
class AddField(FieldOperation):
|
||||||
"""Add a field to a model."""
|
"""Add a field to a model."""
|
||||||
|
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, model_name, name, field, preserve_default=True):
|
def __init__(self, model_name, name, field, preserve_default=True):
|
||||||
self.preserve_default = preserve_default
|
self.preserve_default = preserve_default
|
||||||
super().__init__(model_name, name, field)
|
super().__init__(model_name, name, field)
|
||||||
|
@ -154,6 +156,8 @@ class AddField(FieldOperation):
|
||||||
class RemoveField(FieldOperation):
|
class RemoveField(FieldOperation):
|
||||||
"""Remove a field from a model."""
|
"""Remove a field from a model."""
|
||||||
|
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
|
|
||||||
def deconstruct(self):
|
def deconstruct(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"model_name": self.model_name,
|
"model_name": self.model_name,
|
||||||
|
@ -201,6 +205,8 @@ class AlterField(FieldOperation):
|
||||||
new field.
|
new field.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def __init__(self, model_name, name, field, preserve_default=True):
|
def __init__(self, model_name, name, field, preserve_default=True):
|
||||||
self.preserve_default = preserve_default
|
self.preserve_default = preserve_default
|
||||||
super().__init__(model_name, name, field)
|
super().__init__(model_name, name, field)
|
||||||
|
@ -270,6 +276,8 @@ class AlterField(FieldOperation):
|
||||||
class RenameField(FieldOperation):
|
class RenameField(FieldOperation):
|
||||||
"""Rename a field on the model. Might affect db_column too."""
|
"""Rename a field on the model. Might affect db_column too."""
|
||||||
|
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def __init__(self, model_name, old_name, new_name):
|
def __init__(self, model_name, old_name, new_name):
|
||||||
self.old_name = old_name
|
self.old_name = old_name
|
||||||
self.new_name = new_name
|
self.new_name = new_name
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import models
|
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.state import ModelState
|
||||||
from django.db.migrations.utils import field_references, resolve_relation
|
from django.db.migrations.utils import field_references, resolve_relation
|
||||||
from django.db.models.options import normalize_together
|
from django.db.models.options import normalize_together
|
||||||
|
@ -41,6 +41,7 @@ class ModelOperation(Operation):
|
||||||
class CreateModel(ModelOperation):
|
class CreateModel(ModelOperation):
|
||||||
"""Create a model's table."""
|
"""Create a model's table."""
|
||||||
|
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
serialization_expand_args = ["fields", "options", "managers"]
|
serialization_expand_args = ["fields", "options", "managers"]
|
||||||
|
|
||||||
def __init__(self, name, fields, options=None, bases=None, managers=None):
|
def __init__(self, name, fields, options=None, bases=None, managers=None):
|
||||||
|
@ -347,6 +348,8 @@ class CreateModel(ModelOperation):
|
||||||
class DeleteModel(ModelOperation):
|
class DeleteModel(ModelOperation):
|
||||||
"""Drop a model's table."""
|
"""Drop a model's table."""
|
||||||
|
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
|
|
||||||
def deconstruct(self):
|
def deconstruct(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
|
@ -382,6 +385,8 @@ class DeleteModel(ModelOperation):
|
||||||
class RenameModel(ModelOperation):
|
class RenameModel(ModelOperation):
|
||||||
"""Rename a model."""
|
"""Rename a model."""
|
||||||
|
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def __init__(self, old_name, new_name):
|
def __init__(self, old_name, new_name):
|
||||||
self.old_name = old_name
|
self.old_name = old_name
|
||||||
self.new_name = new_name
|
self.new_name = new_name
|
||||||
|
@ -499,6 +504,8 @@ class RenameModel(ModelOperation):
|
||||||
|
|
||||||
|
|
||||||
class ModelOptionOperation(ModelOperation):
|
class ModelOptionOperation(ModelOperation):
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def reduce(self, operation, app_label):
|
def reduce(self, operation, app_label):
|
||||||
if (
|
if (
|
||||||
isinstance(operation, (self.__class__, DeleteModel))
|
isinstance(operation, (self.__class__, DeleteModel))
|
||||||
|
@ -849,6 +856,8 @@ class IndexOperation(Operation):
|
||||||
class AddIndex(IndexOperation):
|
class AddIndex(IndexOperation):
|
||||||
"""Add an index on a model."""
|
"""Add an index on a model."""
|
||||||
|
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, model_name, index):
|
def __init__(self, model_name, index):
|
||||||
self.model_name = model_name
|
self.model_name = model_name
|
||||||
if not index.name:
|
if not index.name:
|
||||||
|
@ -911,6 +920,8 @@ class AddIndex(IndexOperation):
|
||||||
class RemoveIndex(IndexOperation):
|
class RemoveIndex(IndexOperation):
|
||||||
"""Remove an index from a model."""
|
"""Remove an index from a model."""
|
||||||
|
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
|
|
||||||
def __init__(self, model_name, name):
|
def __init__(self, model_name, name):
|
||||||
self.model_name = model_name
|
self.model_name = model_name
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -954,6 +965,8 @@ class RemoveIndex(IndexOperation):
|
||||||
class RenameIndex(IndexOperation):
|
class RenameIndex(IndexOperation):
|
||||||
"""Rename an index."""
|
"""Rename an index."""
|
||||||
|
|
||||||
|
category = OperationCategory.ALTERATION
|
||||||
|
|
||||||
def __init__(self, model_name, new_name, old_name=None, old_fields=None):
|
def __init__(self, model_name, new_name, old_name=None, old_fields=None):
|
||||||
if not old_name and not old_fields:
|
if not old_name and not old_fields:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -1104,6 +1117,7 @@ class RenameIndex(IndexOperation):
|
||||||
|
|
||||||
|
|
||||||
class AddConstraint(IndexOperation):
|
class AddConstraint(IndexOperation):
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
option_name = "constraints"
|
option_name = "constraints"
|
||||||
|
|
||||||
def __init__(self, model_name, constraint):
|
def __init__(self, model_name, constraint):
|
||||||
|
@ -1154,6 +1168,7 @@ class AddConstraint(IndexOperation):
|
||||||
|
|
||||||
|
|
||||||
class RemoveConstraint(IndexOperation):
|
class RemoveConstraint(IndexOperation):
|
||||||
|
category = OperationCategory.REMOVAL
|
||||||
option_name = "constraints"
|
option_name = "constraints"
|
||||||
|
|
||||||
def __init__(self, model_name, name):
|
def __init__(self, model_name, name):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import router
|
from django.db import router
|
||||||
|
|
||||||
from .base import Operation
|
from .base import Operation, OperationCategory
|
||||||
|
|
||||||
|
|
||||||
class SeparateDatabaseAndState(Operation):
|
class SeparateDatabaseAndState(Operation):
|
||||||
|
@ -11,6 +11,7 @@ class SeparateDatabaseAndState(Operation):
|
||||||
that affect the state or not the database, or so on.
|
that affect the state or not the database, or so on.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
category = OperationCategory.MIXED
|
||||||
serialization_expand_args = ["database_operations", "state_operations"]
|
serialization_expand_args = ["database_operations", "state_operations"]
|
||||||
|
|
||||||
def __init__(self, database_operations=None, state_operations=None):
|
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.
|
by this SQL change, in case it's custom column/table creation/deletion.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
category = OperationCategory.SQL
|
||||||
noop = ""
|
noop = ""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -138,6 +140,7 @@ class RunPython(Operation):
|
||||||
Run Python code in a context suitable for doing versioned ORM operations.
|
Run Python code in a context suitable for doing versioned ORM operations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
category = OperationCategory.PYTHON
|
||||||
reduces_to_sql = False
|
reduces_to_sql = False
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
@ -241,8 +241,8 @@ You should see something similar to the following:
|
||||||
|
|
||||||
Migrations for 'polls':
|
Migrations for 'polls':
|
||||||
polls/migrations/0001_initial.py
|
polls/migrations/0001_initial.py
|
||||||
- Create model Question
|
+ Create model Question
|
||||||
- Create model Choice
|
+ Create model Choice
|
||||||
|
|
||||||
By running ``makemigrations``, you're telling Django that you've made
|
By running ``makemigrations``, you're telling Django that you've made
|
||||||
some changes to your models (in this case, you've made new ones) and that
|
some changes to your models (in this case, you've made new ones) and that
|
||||||
|
|
|
@ -241,7 +241,7 @@ create a database migration:
|
||||||
$ python manage.py makemigrations
|
$ python manage.py makemigrations
|
||||||
Migrations for 'world':
|
Migrations for 'world':
|
||||||
world/migrations/0001_initial.py:
|
world/migrations/0001_initial.py:
|
||||||
- Create model WorldBorder
|
+ Create model WorldBorder
|
||||||
|
|
||||||
Let's look at the SQL that will generate the table for the ``WorldBorder``
|
Let's look at the SQL that will generate the table for the ``WorldBorder``
|
||||||
model:
|
model:
|
||||||
|
|
|
@ -475,6 +475,42 @@ operations.
|
||||||
For an example using ``SeparateDatabaseAndState``, see
|
For an example using ``SeparateDatabaseAndState``, see
|
||||||
:ref:`changing-a-manytomanyfield-to-use-a-through-model`.
|
:ref:`changing-a-manytomanyfield-to-use-a-through-model`.
|
||||||
|
|
||||||
|
Operation category
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. versionadded:: 5.1
|
||||||
|
|
||||||
|
.. currentmodule:: django.db.migrations.operations.base
|
||||||
|
|
||||||
|
.. class:: OperationCategory
|
||||||
|
|
||||||
|
Categories of migration operation used by the :djadmin:`makemigrations`
|
||||||
|
command to display meaningful symbols.
|
||||||
|
|
||||||
|
.. attribute:: ADDITION
|
||||||
|
|
||||||
|
*Symbol*: ``+``
|
||||||
|
|
||||||
|
.. attribute:: REMOVAL
|
||||||
|
|
||||||
|
*Symbol*: ``-``
|
||||||
|
|
||||||
|
.. attribute:: ALTERATION
|
||||||
|
|
||||||
|
*Symbol*: ``~``
|
||||||
|
|
||||||
|
.. attribute:: PYTHON
|
||||||
|
|
||||||
|
*Symbol*: ``p``
|
||||||
|
|
||||||
|
.. attribute:: SQL
|
||||||
|
|
||||||
|
*Symbol*: ``s``
|
||||||
|
|
||||||
|
.. attribute:: MIXED
|
||||||
|
|
||||||
|
*Symbol*: ``?``
|
||||||
|
|
||||||
.. _writing-your-own-migration-operation:
|
.. _writing-your-own-migration-operation:
|
||||||
|
|
||||||
Writing your own
|
Writing your own
|
||||||
|
@ -495,6 +531,10 @@ structure of an ``Operation`` looks like this::
|
||||||
# If this is False, Django will refuse to reverse past this operation.
|
# If this is False, Django will refuse to reverse past this operation.
|
||||||
reversible = False
|
reversible = False
|
||||||
|
|
||||||
|
# This categorizes the operation. The corresponding symbol will be
|
||||||
|
# display by the makemigrations command.
|
||||||
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, arg1, arg2):
|
def __init__(self, arg1, arg2):
|
||||||
# Operations are usually instantiated with arguments in migration
|
# Operations are usually instantiated with arguments in migration
|
||||||
# files. Store the values of them on self for later use.
|
# files. Store the values of them on self for later use.
|
||||||
|
@ -516,7 +556,7 @@ structure of an ``Operation`` looks like this::
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
# This is used to describe what the operation does in console output.
|
# This is used to describe what the operation does.
|
||||||
return "Custom Operation"
|
return "Custom Operation"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -178,12 +178,17 @@ Logging
|
||||||
Management Commands
|
Management Commands
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* :djadmin:`makemigrations` command now displays meaningful symbols for each
|
||||||
|
operation to highlight :class:`operation categories
|
||||||
|
<django.db.migrations.operations.base.OperationCategory>`.
|
||||||
|
|
||||||
Migrations
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* The new ``Operation.category`` attribute allows specifying an
|
||||||
|
:class:`operation category
|
||||||
|
<django.db.migrations.operations.base.OperationCategory>` used by the
|
||||||
|
:djadmin:`makemigrations` to display a meaningful symbol for the operation.
|
||||||
|
|
||||||
Models
|
Models
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
|
@ -118,7 +118,7 @@ field and remove a model - and then run :djadmin:`makemigrations`:
|
||||||
$ python manage.py makemigrations
|
$ python manage.py makemigrations
|
||||||
Migrations for 'books':
|
Migrations for 'books':
|
||||||
books/migrations/0003_auto.py:
|
books/migrations/0003_auto.py:
|
||||||
- Alter field author on book
|
~ Alter field author on book
|
||||||
|
|
||||||
Your models will be scanned and compared to the versions currently
|
Your models will be scanned and compared to the versions currently
|
||||||
contained in your migration files, and then a new set of migrations
|
contained in your migration files, and then a new set of migrations
|
||||||
|
|
|
@ -2141,7 +2141,7 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Normal --dry-run output
|
# Normal --dry-run output
|
||||||
self.assertIn("- Add field silly_char to sillymodel", out.getvalue())
|
self.assertIn("+ Add field silly_char to sillymodel", out.getvalue())
|
||||||
|
|
||||||
# Additional output caused by verbosity 3
|
# Additional output caused by verbosity 3
|
||||||
# The complete migrations file that would be written
|
# The complete migrations file that would be written
|
||||||
|
@ -2171,7 +2171,7 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
)
|
)
|
||||||
initial_file = os.path.join(migration_dir, "0001_initial.py")
|
initial_file = os.path.join(migration_dir, "0001_initial.py")
|
||||||
self.assertEqual(out.getvalue(), f"{initial_file}\n")
|
self.assertEqual(out.getvalue(), f"{initial_file}\n")
|
||||||
self.assertIn(" - Create model ModelWithCustomBase\n", err.getvalue())
|
self.assertIn(" + Create model ModelWithCustomBase\n", err.getvalue())
|
||||||
|
|
||||||
@mock.patch("builtins.input", return_value="Y")
|
@mock.patch("builtins.input", return_value="Y")
|
||||||
def test_makemigrations_scriptable_merge(self, mock_input):
|
def test_makemigrations_scriptable_merge(self, mock_input):
|
||||||
|
@ -2216,7 +2216,7 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
self.assertTrue(os.path.exists(initial_file))
|
self.assertTrue(os.path.exists(initial_file))
|
||||||
|
|
||||||
# Command output indicates the migration is created.
|
# Command output indicates the migration is created.
|
||||||
self.assertIn(" - Create model SillyModel", out.getvalue())
|
self.assertIn(" + Create model SillyModel", out.getvalue())
|
||||||
|
|
||||||
@override_settings(MIGRATION_MODULES={"migrations": "some.nonexistent.path"})
|
@override_settings(MIGRATION_MODULES={"migrations": "some.nonexistent.path"})
|
||||||
def test_makemigrations_migrations_modules_nonexistent_toplevel_package(self):
|
def test_makemigrations_migrations_modules_nonexistent_toplevel_package(self):
|
||||||
|
@ -2321,12 +2321,12 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
out.getvalue().lower(),
|
out.getvalue().lower(),
|
||||||
"merging conflicting_app_with_dependencies\n"
|
"merging conflicting_app_with_dependencies\n"
|
||||||
" branch 0002_conflicting_second\n"
|
" branch 0002_conflicting_second\n"
|
||||||
" - create model something\n"
|
" + create model something\n"
|
||||||
" branch 0002_second\n"
|
" branch 0002_second\n"
|
||||||
" - delete model tribble\n"
|
" - delete model tribble\n"
|
||||||
" - remove field silly_field from author\n"
|
" - remove field silly_field from author\n"
|
||||||
" - add field rating to author\n"
|
" + add field rating to author\n"
|
||||||
" - create model book\n"
|
" + create model book\n"
|
||||||
"\n"
|
"\n"
|
||||||
"merging will only work if the operations printed above do not "
|
"merging will only work if the operations printed above do not "
|
||||||
"conflict\n"
|
"conflict\n"
|
||||||
|
|
|
@ -4,6 +4,7 @@ from decimal import Decimal
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db import IntegrityError, connection, migrations, models, transaction
|
from django.db import IntegrityError, connection, migrations, models, transaction
|
||||||
from django.db.migrations.migration import Migration
|
from django.db.migrations.migration import Migration
|
||||||
|
from django.db.migrations.operations.base import Operation
|
||||||
from django.db.migrations.operations.fields import FieldOperation
|
from django.db.migrations.operations.fields import FieldOperation
|
||||||
from django.db.migrations.state import ModelState, ProjectState
|
from django.db.migrations.state import ModelState, ProjectState
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
|
@ -47,6 +48,7 @@ class OperationTests(OperationTestBase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Create model Pony")
|
self.assertEqual(operation.describe(), "Create model Pony")
|
||||||
|
self.assertEqual(operation.formatted_description(), "+ Create model Pony")
|
||||||
self.assertEqual(operation.migration_name_fragment, "pony")
|
self.assertEqual(operation.migration_name_fragment, "pony")
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
|
@ -710,6 +712,7 @@ class OperationTests(OperationTestBase):
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
operation = migrations.DeleteModel("Pony")
|
operation = migrations.DeleteModel("Pony")
|
||||||
self.assertEqual(operation.describe(), "Delete model Pony")
|
self.assertEqual(operation.describe(), "Delete model Pony")
|
||||||
|
self.assertEqual(operation.formatted_description(), "- Delete model Pony")
|
||||||
self.assertEqual(operation.migration_name_fragment, "delete_pony")
|
self.assertEqual(operation.migration_name_fragment, "delete_pony")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_dlmo", new_state)
|
operation.state_forwards("test_dlmo", new_state)
|
||||||
|
@ -790,6 +793,9 @@ class OperationTests(OperationTestBase):
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
operation = migrations.RenameModel("Pony", "Horse")
|
operation = migrations.RenameModel("Pony", "Horse")
|
||||||
self.assertEqual(operation.describe(), "Rename model Pony to Horse")
|
self.assertEqual(operation.describe(), "Rename model Pony to Horse")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "~ Rename model Pony to Horse"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "rename_pony_horse")
|
self.assertEqual(operation.migration_name_fragment, "rename_pony_horse")
|
||||||
# Test initial state and database
|
# Test initial state and database
|
||||||
self.assertIn(("test_rnmo", "pony"), project_state.models)
|
self.assertIn(("test_rnmo", "pony"), project_state.models)
|
||||||
|
@ -1350,6 +1356,9 @@ class OperationTests(OperationTestBase):
|
||||||
models.FloatField(null=True, default=5),
|
models.FloatField(null=True, default=5),
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Add field height to Pony")
|
self.assertEqual(operation.describe(), "Add field height to Pony")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "+ Add field height to Pony"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "pony_height")
|
self.assertEqual(operation.migration_name_fragment, "pony_height")
|
||||||
project_state, new_state = self.make_test_state("test_adfl", operation)
|
project_state, new_state = self.make_test_state("test_adfl", operation)
|
||||||
self.assertEqual(len(new_state.models["test_adfl", "pony"].fields), 6)
|
self.assertEqual(len(new_state.models["test_adfl", "pony"].fields), 6)
|
||||||
|
@ -1906,6 +1915,9 @@ class OperationTests(OperationTestBase):
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
operation = migrations.RemoveField("Pony", "pink")
|
operation = migrations.RemoveField("Pony", "pink")
|
||||||
self.assertEqual(operation.describe(), "Remove field pink from Pony")
|
self.assertEqual(operation.describe(), "Remove field pink from Pony")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "- Remove field pink from Pony"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "remove_pony_pink")
|
self.assertEqual(operation.migration_name_fragment, "remove_pony_pink")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_rmfl", new_state)
|
operation.state_forwards("test_rmfl", new_state)
|
||||||
|
@ -1952,6 +1964,10 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.describe(), "Rename table for Pony to test_almota_pony_2"
|
operation.describe(), "Rename table for Pony to test_almota_pony_2"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"~ Rename table for Pony to test_almota_pony_2",
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "alter_pony_table")
|
self.assertEqual(operation.migration_name_fragment, "alter_pony_table")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_almota", new_state)
|
operation.state_forwards("test_almota", new_state)
|
||||||
|
@ -2093,6 +2109,9 @@ class OperationTests(OperationTestBase):
|
||||||
"Pony", "pink", models.IntegerField(null=True)
|
"Pony", "pink", models.IntegerField(null=True)
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Alter field pink on Pony")
|
self.assertEqual(operation.describe(), "Alter field pink on Pony")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "~ Alter field pink on Pony"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "alter_pony_pink")
|
self.assertEqual(operation.migration_name_fragment, "alter_pony_pink")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_alfl", new_state)
|
operation.state_forwards("test_alfl", new_state)
|
||||||
|
@ -2403,6 +2422,9 @@ class OperationTests(OperationTestBase):
|
||||||
# Add table comment.
|
# Add table comment.
|
||||||
operation = migrations.AlterModelTableComment("Pony", "Custom pony comment")
|
operation = migrations.AlterModelTableComment("Pony", "Custom pony comment")
|
||||||
self.assertEqual(operation.describe(), "Alter Pony table comment")
|
self.assertEqual(operation.describe(), "Alter Pony table comment")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "~ Alter Pony table comment"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "alter_pony_table_comment")
|
self.assertEqual(operation.migration_name_fragment, "alter_pony_table_comment")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards(app_label, new_state)
|
operation.state_forwards(app_label, new_state)
|
||||||
|
@ -3073,6 +3095,9 @@ class OperationTests(OperationTestBase):
|
||||||
project_state = self.set_up_test_model("test_rnfl")
|
project_state = self.set_up_test_model("test_rnfl")
|
||||||
operation = migrations.RenameField("Pony", "pink", "blue")
|
operation = migrations.RenameField("Pony", "pink", "blue")
|
||||||
self.assertEqual(operation.describe(), "Rename field pink on Pony to blue")
|
self.assertEqual(operation.describe(), "Rename field pink on Pony to blue")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "~ Rename field pink on Pony to blue"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "rename_pink_pony_blue")
|
self.assertEqual(operation.migration_name_fragment, "rename_pink_pony_blue")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_rnfl", new_state)
|
operation.state_forwards("test_rnfl", new_state)
|
||||||
|
@ -3326,6 +3351,10 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.describe(), "Alter unique_together for Pony (1 constraint(s))"
|
operation.describe(), "Alter unique_together for Pony (1 constraint(s))"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"~ Alter unique_together for Pony (1 constraint(s))",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
"alter_pony_unique_together",
|
"alter_pony_unique_together",
|
||||||
|
@ -3478,6 +3507,10 @@ class OperationTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
"Create index test_adin_pony_pink_idx on field(s) pink of model Pony",
|
"Create index test_adin_pony_pink_idx on field(s) pink of model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"+ Create index test_adin_pony_pink_idx on field(s) pink of model Pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
"pony_test_adin_pony_pink_idx",
|
"pony_test_adin_pony_pink_idx",
|
||||||
|
@ -3511,6 +3544,9 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertIndexExists("test_rmin_pony", ["pink", "weight"])
|
self.assertIndexExists("test_rmin_pony", ["pink", "weight"])
|
||||||
operation = migrations.RemoveIndex("Pony", "pony_test_idx")
|
operation = migrations.RemoveIndex("Pony", "pony_test_idx")
|
||||||
self.assertEqual(operation.describe(), "Remove index pony_test_idx from Pony")
|
self.assertEqual(operation.describe(), "Remove index pony_test_idx from Pony")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "- Remove index pony_test_idx from Pony"
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
"remove_pony_pony_test_idx",
|
"remove_pony_pony_test_idx",
|
||||||
|
@ -3565,6 +3601,10 @@ class OperationTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
"Rename index pony_pink_idx on Pony to new_pony_test_idx",
|
"Rename index pony_pink_idx on Pony to new_pony_test_idx",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"~ Rename index pony_pink_idx on Pony to new_pony_test_idx",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
"rename_pony_pink_idx_new_pony_test_idx",
|
"rename_pony_pink_idx_new_pony_test_idx",
|
||||||
|
@ -3807,6 +3847,10 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.describe(), "Alter index_together for Pony (0 constraint(s))"
|
operation.describe(), "Alter index_together for Pony (0 constraint(s))"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"~ Alter index_together for Pony (0 constraint(s))",
|
||||||
|
)
|
||||||
|
|
||||||
def test_add_constraint(self):
|
def test_add_constraint(self):
|
||||||
project_state = self.set_up_test_model("test_addconstraint")
|
project_state = self.set_up_test_model("test_addconstraint")
|
||||||
|
@ -3819,6 +3863,10 @@ class OperationTests(OperationTestBase):
|
||||||
gt_operation.describe(),
|
gt_operation.describe(),
|
||||||
"Create constraint test_add_constraint_pony_pink_gt_2 on model Pony",
|
"Create constraint test_add_constraint_pony_pink_gt_2 on model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
gt_operation.formatted_description(),
|
||||||
|
"+ Create constraint test_add_constraint_pony_pink_gt_2 on model Pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
gt_operation.migration_name_fragment,
|
gt_operation.migration_name_fragment,
|
||||||
"pony_test_add_constraint_pony_pink_gt_2",
|
"pony_test_add_constraint_pony_pink_gt_2",
|
||||||
|
@ -4024,6 +4072,10 @@ class OperationTests(OperationTestBase):
|
||||||
gt_operation.describe(),
|
gt_operation.describe(),
|
||||||
"Remove constraint test_remove_constraint_pony_pink_gt_2 from model Pony",
|
"Remove constraint test_remove_constraint_pony_pink_gt_2 from model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
gt_operation.formatted_description(),
|
||||||
|
"- Remove constraint test_remove_constraint_pony_pink_gt_2 from model Pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
gt_operation.migration_name_fragment,
|
gt_operation.migration_name_fragment,
|
||||||
"remove_pony_test_remove_constraint_pony_pink_gt_2",
|
"remove_pony_test_remove_constraint_pony_pink_gt_2",
|
||||||
|
@ -4564,6 +4616,9 @@ class OperationTests(OperationTestBase):
|
||||||
"Pony", {"permissions": [("can_groom", "Can groom")]}
|
"Pony", {"permissions": [("can_groom", "Can groom")]}
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Change Meta options on Pony")
|
self.assertEqual(operation.describe(), "Change Meta options on Pony")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "~ Change Meta options on Pony"
|
||||||
|
)
|
||||||
self.assertEqual(operation.migration_name_fragment, "alter_pony_options")
|
self.assertEqual(operation.migration_name_fragment, "alter_pony_options")
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_almoop", new_state)
|
operation.state_forwards("test_almoop", new_state)
|
||||||
|
@ -4630,6 +4685,10 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.describe(), "Set order_with_respect_to on Rider to pony"
|
operation.describe(), "Set order_with_respect_to on Rider to pony"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"~ Set order_with_respect_to on Rider to pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
"alter_rider_order_with_respect_to",
|
"alter_rider_order_with_respect_to",
|
||||||
|
@ -4705,6 +4764,7 @@ class OperationTests(OperationTestBase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Change managers on Pony")
|
self.assertEqual(operation.describe(), "Change managers on Pony")
|
||||||
|
self.assertEqual(operation.formatted_description(), "~ Change managers on Pony")
|
||||||
self.assertEqual(operation.migration_name_fragment, "alter_pony_managers")
|
self.assertEqual(operation.migration_name_fragment, "alter_pony_managers")
|
||||||
managers = project_state.models["test_almoma", "pony"].managers
|
managers = project_state.models["test_almoma", "pony"].managers
|
||||||
self.assertEqual(managers, [])
|
self.assertEqual(managers, [])
|
||||||
|
@ -4840,6 +4900,7 @@ class OperationTests(OperationTestBase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Raw SQL operation")
|
self.assertEqual(operation.describe(), "Raw SQL operation")
|
||||||
|
self.assertEqual(operation.formatted_description(), "s Raw SQL operation")
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_runsql", new_state)
|
operation.state_forwards("test_runsql", new_state)
|
||||||
|
@ -5034,6 +5095,7 @@ class OperationTests(OperationTestBase):
|
||||||
inner_method, reverse_code=inner_method_reverse
|
inner_method, reverse_code=inner_method_reverse
|
||||||
)
|
)
|
||||||
self.assertEqual(operation.describe(), "Raw Python operation")
|
self.assertEqual(operation.describe(), "Raw Python operation")
|
||||||
|
self.assertEqual(operation.formatted_description(), "p Raw Python operation")
|
||||||
# Test the state alteration does nothing
|
# Test the state alteration does nothing
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_runpython", new_state)
|
operation.state_forwards("test_runpython", new_state)
|
||||||
|
@ -5565,6 +5627,10 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.describe(), "Custom state/database change combination"
|
operation.describe(), "Custom state/database change combination"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"? Custom state/database change combination",
|
||||||
|
)
|
||||||
# Test the state alteration
|
# Test the state alteration
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
operation.state_forwards("test_separatedatabaseandstate", new_state)
|
operation.state_forwards("test_separatedatabaseandstate", new_state)
|
||||||
|
@ -6073,3 +6139,9 @@ class FieldOperationTests(SimpleTestCase):
|
||||||
self.assertIs(
|
self.assertIs(
|
||||||
operation.references_field("Through", "second", "migrations"), True
|
operation.references_field("Through", "second", "migrations"), True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseOperationTests(SimpleTestCase):
|
||||||
|
def test_formatted_description_no_category(self):
|
||||||
|
operation = Operation()
|
||||||
|
self.assertEqual(operation.formatted_description(), "? Operation: ((), {})")
|
||||||
|
|
|
@ -59,6 +59,10 @@ class AddIndexConcurrentlyTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
"Concurrently create index pony_pink_idx on field(s) pink of model Pony",
|
"Concurrently create index pony_pink_idx on field(s) pink of model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"+ Concurrently create index pony_pink_idx on field(s) pink of model Pony",
|
||||||
|
)
|
||||||
operation.state_forwards(self.app_label, new_state)
|
operation.state_forwards(self.app_label, new_state)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(new_state.models[self.app_label, "pony"].options["indexes"]), 1
|
len(new_state.models[self.app_label, "pony"].options["indexes"]), 1
|
||||||
|
@ -154,6 +158,10 @@ class RemoveIndexConcurrentlyTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
"Concurrently remove index pony_pink_idx from Pony",
|
"Concurrently remove index pony_pink_idx from Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
"- Concurrently remove index pony_pink_idx from Pony",
|
||||||
|
)
|
||||||
operation.state_forwards(self.app_label, new_state)
|
operation.state_forwards(self.app_label, new_state)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(new_state.models[self.app_label, "pony"].options["indexes"]), 0
|
len(new_state.models[self.app_label, "pony"].options["indexes"]), 0
|
||||||
|
@ -190,6 +198,9 @@ class CreateExtensionTests(PostgreSQLTestCase):
|
||||||
@override_settings(DATABASE_ROUTERS=[NoMigrationRouter()])
|
@override_settings(DATABASE_ROUTERS=[NoMigrationRouter()])
|
||||||
def test_no_allow_migrate(self):
|
def test_no_allow_migrate(self):
|
||||||
operation = CreateExtension("tablefunc")
|
operation = CreateExtension("tablefunc")
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(), "+ Creates extension tablefunc"
|
||||||
|
)
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
# Don't create an extension.
|
# Don't create an extension.
|
||||||
|
@ -287,6 +298,7 @@ class CreateCollationTests(PostgreSQLTestCase):
|
||||||
operation = CreateCollation("C_test", locale="C")
|
operation = CreateCollation("C_test", locale="C")
|
||||||
self.assertEqual(operation.migration_name_fragment, "create_collation_c_test")
|
self.assertEqual(operation.migration_name_fragment, "create_collation_c_test")
|
||||||
self.assertEqual(operation.describe(), "Create collation C_test")
|
self.assertEqual(operation.describe(), "Create collation C_test")
|
||||||
|
self.assertEqual(operation.formatted_description(), "+ Create collation C_test")
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
# Create a collation.
|
# Create a collation.
|
||||||
|
@ -418,6 +430,7 @@ class RemoveCollationTests(PostgreSQLTestCase):
|
||||||
operation = RemoveCollation("C_test", locale="C")
|
operation = RemoveCollation("C_test", locale="C")
|
||||||
self.assertEqual(operation.migration_name_fragment, "remove_collation_c_test")
|
self.assertEqual(operation.migration_name_fragment, "remove_collation_c_test")
|
||||||
self.assertEqual(operation.describe(), "Remove collation C_test")
|
self.assertEqual(operation.describe(), "Remove collation C_test")
|
||||||
|
self.assertEqual(operation.formatted_description(), "- Remove collation C_test")
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
new_state = project_state.clone()
|
new_state = project_state.clone()
|
||||||
# Remove a collation.
|
# Remove a collation.
|
||||||
|
@ -470,6 +483,10 @@ class AddConstraintNotValidTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
f"Create not valid constraint {constraint_name} on model Pony",
|
f"Create not valid constraint {constraint_name} on model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
f"+ Create not valid constraint {constraint_name} on model Pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
f"pony_{constraint_name}_not_valid",
|
f"pony_{constraint_name}_not_valid",
|
||||||
|
@ -530,6 +547,10 @@ class ValidateConstraintTests(OperationTestBase):
|
||||||
operation.describe(),
|
operation.describe(),
|
||||||
f"Validate constraint {constraint_name} on model Pony",
|
f"Validate constraint {constraint_name} on model Pony",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
operation.formatted_description(),
|
||||||
|
f"~ Validate constraint {constraint_name} on model Pony",
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.migration_name_fragment,
|
operation.migration_name_fragment,
|
||||||
f"pony_validate_{constraint_name}",
|
f"pony_validate_{constraint_name}",
|
||||||
|
|
Loading…
Reference in New Issue