Refs #27236 -- Reverted "Refs #27236 -- Added generic mechanism to handle the deprecation of migration operations."
This reverts commit 41019e48bb
.
This commit is contained in:
parent
c773d5794e
commit
a1e9e9abc5
|
@ -19,7 +19,6 @@ import django.core.checks.caches # NOQA isort:skip
|
||||||
import django.core.checks.compatibility.django_4_0 # NOQA isort:skip
|
import django.core.checks.compatibility.django_4_0 # NOQA isort:skip
|
||||||
import django.core.checks.database # NOQA isort:skip
|
import django.core.checks.database # NOQA isort:skip
|
||||||
import django.core.checks.files # NOQA isort:skip
|
import django.core.checks.files # NOQA isort:skip
|
||||||
import django.core.checks.migrations # NOQA isort:skip
|
|
||||||
import django.core.checks.model_checks # NOQA isort:skip
|
import django.core.checks.model_checks # NOQA isort:skip
|
||||||
import django.core.checks.security.base # NOQA isort:skip
|
import django.core.checks.security.base # NOQA isort:skip
|
||||||
import django.core.checks.security.csrf # NOQA isort:skip
|
import django.core.checks.security.csrf # NOQA isort:skip
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
from django.core.checks import Tags, register
|
|
||||||
|
|
||||||
|
|
||||||
@register(Tags.migrations)
|
|
||||||
def check_migration_operations(**kwargs):
|
|
||||||
from django.db.migrations.loader import MigrationLoader
|
|
||||||
|
|
||||||
errors = []
|
|
||||||
loader = MigrationLoader(None, ignore_no_migrations=True)
|
|
||||||
for migration in loader.disk_migrations.values():
|
|
||||||
errors.extend(migration.check())
|
|
||||||
return errors
|
|
|
@ -15,7 +15,6 @@ class Tags:
|
||||||
compatibility = "compatibility"
|
compatibility = "compatibility"
|
||||||
database = "database"
|
database = "database"
|
||||||
files = "files"
|
files = "files"
|
||||||
migrations = "migrations"
|
|
||||||
models = "models"
|
models = "models"
|
||||||
security = "security"
|
security = "security"
|
||||||
signals = "signals"
|
signals = "signals"
|
||||||
|
|
|
@ -219,12 +219,6 @@ class Migration:
|
||||||
name = new_name
|
name = new_name
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def check(self):
|
|
||||||
errors = []
|
|
||||||
for operation in self.operations:
|
|
||||||
errors.extend(operation.check_deprecation_details())
|
|
||||||
return errors
|
|
||||||
|
|
||||||
|
|
||||||
class SwappableTuple(tuple):
|
class SwappableTuple(tuple):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
from django.db import router
|
from django.db import router
|
||||||
from django.utils.deprecation import DeprecationForHistoricalMigrationMixin
|
|
||||||
|
|
||||||
|
|
||||||
class Operation(DeprecationForHistoricalMigrationMixin):
|
class Operation:
|
||||||
"""
|
"""
|
||||||
Base class for migration operations.
|
Base class for migration operations.
|
||||||
|
|
||||||
|
@ -34,8 +33,6 @@ class Operation(DeprecationForHistoricalMigrationMixin):
|
||||||
|
|
||||||
serialization_expand_args = []
|
serialization_expand_args = []
|
||||||
|
|
||||||
check_type = "migrations"
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -83,7 +83,6 @@ Django's system checks are organized using the following tags:
|
||||||
you specify configured database aliases using the ``--database`` option when
|
you specify configured database aliases using the ``--database`` option when
|
||||||
calling the :djadmin:`check` command.
|
calling the :djadmin:`check` command.
|
||||||
* ``files``: Checks files related configuration.
|
* ``files``: Checks files related configuration.
|
||||||
* ``migrations``: Checks of migration operations.
|
|
||||||
* ``models``: Checks of model, field, and manager definitions.
|
* ``models``: Checks of model, field, and manager definitions.
|
||||||
* ``security``: Checks security related configuration.
|
* ``security``: Checks security related configuration.
|
||||||
* ``signals``: Checks on signal declarations and handler registrations.
|
* ``signals``: Checks on signal declarations and handler registrations.
|
||||||
|
@ -95,10 +94,6 @@ Django's system checks are organized using the following tags:
|
||||||
|
|
||||||
Some checks may be registered with multiple tags.
|
Some checks may be registered with multiple tags.
|
||||||
|
|
||||||
.. versionchanged:: 4.2
|
|
||||||
|
|
||||||
The ``migrations`` tag was added.
|
|
||||||
|
|
||||||
Core system checks
|
Core system checks
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
|
@ -172,8 +172,7 @@ Management Commands
|
||||||
Migrations
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
* The new :ref:`generic mechanism <migrations-removing-operation>` allows
|
* ...
|
||||||
handling the deprecation of migration operations.
|
|
||||||
|
|
||||||
Models
|
Models
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
|
@ -128,18 +128,18 @@ The code below is equivalent to the code above::
|
||||||
|
|
||||||
.. _field-checking:
|
.. _field-checking:
|
||||||
|
|
||||||
Field, model, manager, migration, and database checks
|
Field, model, manager, and database checks
|
||||||
-----------------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
In some cases, you won't need to register your check function -- you can
|
In some cases, you won't need to register your check function -- you can
|
||||||
piggyback on an existing registration.
|
piggyback on an existing registration.
|
||||||
|
|
||||||
Fields, models, model managers, migrations, and database backends all implement
|
Fields, models, model managers, and database backends all implement a
|
||||||
a ``check()`` method that is already registered with the check framework. If
|
``check()`` method that is already registered with the check framework. If you
|
||||||
you want to add extra checks, you can extend the implementation on the base
|
want to add extra checks, you can extend the implementation on the base class,
|
||||||
class, perform any extra checks you need, and append any messages to those
|
perform any extra checks you need, and append any messages to those generated
|
||||||
generated by the base class. It's recommended that you delegate each check to
|
by the base class. It's recommended that you delegate each check to separate
|
||||||
separate methods.
|
methods.
|
||||||
|
|
||||||
Consider an example where you are implementing a custom field named
|
Consider an example where you are implementing a custom field named
|
||||||
``RangedIntegerField``. This field adds ``min`` and ``max`` arguments to the
|
``RangedIntegerField``. This field adds ``min`` and ``max`` arguments to the
|
||||||
|
@ -194,10 +194,6 @@ the only difference is that the check is a classmethod, not an instance method::
|
||||||
# ... your own checks ...
|
# ... your own checks ...
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
.. versionchanged:: 4.2
|
|
||||||
|
|
||||||
Migration checks were added.
|
|
||||||
|
|
||||||
Writing tests
|
Writing tests
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -503,56 +503,6 @@ database migrations such as ``__init__()``, ``deconstruct()``, and
|
||||||
which reference the field exist. For example, after squashing migrations and
|
which reference the field exist. For example, after squashing migrations and
|
||||||
removing the old ones, you should be able to remove the field completely.
|
removing the old ones, you should be able to remove the field completely.
|
||||||
|
|
||||||
.. _migrations-removing-operation:
|
|
||||||
|
|
||||||
Considerations when removing migration operations
|
|
||||||
=================================================
|
|
||||||
|
|
||||||
.. versionadded:: 4.2
|
|
||||||
|
|
||||||
Removing custom operations from your project or third-party app will cause a
|
|
||||||
problem if they are referenced in old migrations.
|
|
||||||
|
|
||||||
To help with this situation, Django provides some operation attributes to
|
|
||||||
assist with operation deprecation using the :doc:`system checks framework
|
|
||||||
</topics/checks>`.
|
|
||||||
|
|
||||||
Add the ``system_check_deprecated_details`` attribute to your operation similar
|
|
||||||
to the following::
|
|
||||||
|
|
||||||
class MyCustomOperation(Operation):
|
|
||||||
system_check_deprecated_details = {
|
|
||||||
"msg": (
|
|
||||||
"MyCustomOperation has been deprecated. Support for it "
|
|
||||||
"(except in historical migrations) will be removed in "
|
|
||||||
"Django 5.1."
|
|
||||||
),
|
|
||||||
"hint": "Use DifferentOperation instead.", # optional
|
|
||||||
"id": "migrations.W900", # pick a unique ID for your operation.
|
|
||||||
}
|
|
||||||
|
|
||||||
After a deprecation period of your choosing (two or three feature releases for
|
|
||||||
operations in Django itself), change the ``system_check_deprecated_details``
|
|
||||||
attribute to ``system_check_removed_details`` and update the dictionary similar
|
|
||||||
to::
|
|
||||||
|
|
||||||
class MyCustomOperation(Operation):
|
|
||||||
system_check_removed_details = {
|
|
||||||
"msg": (
|
|
||||||
"MyCustomOperation has been removed except for support in "
|
|
||||||
"historical migrations."
|
|
||||||
),
|
|
||||||
"hint': "Use DifferentOperation instead.",
|
|
||||||
"id": "migrations.E900", # pick a unique ID for your operation.
|
|
||||||
}
|
|
||||||
|
|
||||||
You should keep the operation's methods that are required for it to operate in
|
|
||||||
database migrations such as ``__init__()``, ``state_forwards()``,
|
|
||||||
``database_forwards()``, and ``database_backwards()``. Keep this stub operation
|
|
||||||
for as long as any migrations which reference the operation exist. For example,
|
|
||||||
after squashing migrations and removing the old ones, you should be able to
|
|
||||||
remove the operation completely.
|
|
||||||
|
|
||||||
.. _data-migrations:
|
.. _data-migrations:
|
||||||
|
|
||||||
Data Migrations
|
Data Migrations
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
from django.core import checks
|
|
||||||
from django.db import migrations
|
|
||||||
from django.db.migrations.operations.base import Operation
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
|
|
||||||
class DeprecatedMigrationOperationTests(TestCase):
|
|
||||||
def test_default_operation(self):
|
|
||||||
class MyOperation(Operation):
|
|
||||||
system_check_deprecated_details = {}
|
|
||||||
|
|
||||||
my_operation = MyOperation()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
operations = [my_operation]
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
Migration("name", "app_label").check(),
|
|
||||||
[
|
|
||||||
checks.Warning(
|
|
||||||
msg="MyOperation has been deprecated.",
|
|
||||||
obj=my_operation,
|
|
||||||
id="migrations.WXXX",
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_user_specified_details(self):
|
|
||||||
class MyOperation(Operation):
|
|
||||||
system_check_deprecated_details = {
|
|
||||||
"msg": "This operation is deprecated and will be removed soon.",
|
|
||||||
"hint": "Use something else.",
|
|
||||||
"id": "migrations.W999",
|
|
||||||
}
|
|
||||||
|
|
||||||
my_operation = MyOperation()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
operations = [my_operation]
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
Migration("name", "app_label").check(),
|
|
||||||
[
|
|
||||||
checks.Warning(
|
|
||||||
msg="This operation is deprecated and will be removed soon.",
|
|
||||||
obj=my_operation,
|
|
||||||
hint="Use something else.",
|
|
||||||
id="migrations.W999",
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class RemovedMigrationOperationTests(TestCase):
|
|
||||||
def test_default_operation(self):
|
|
||||||
class MyOperation(Operation):
|
|
||||||
system_check_removed_details = {}
|
|
||||||
|
|
||||||
my_operation = MyOperation()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
operations = [my_operation]
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
Migration("name", "app_label").check(),
|
|
||||||
[
|
|
||||||
checks.Error(
|
|
||||||
msg=(
|
|
||||||
"MyOperation has been removed except for support in historical "
|
|
||||||
"migrations."
|
|
||||||
),
|
|
||||||
obj=my_operation,
|
|
||||||
id="migrations.EXXX",
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_user_specified_details(self):
|
|
||||||
class MyOperation(Operation):
|
|
||||||
system_check_removed_details = {
|
|
||||||
"msg": "Support for this operation is gone.",
|
|
||||||
"hint": "Use something else.",
|
|
||||||
"id": "migrations.E999",
|
|
||||||
}
|
|
||||||
|
|
||||||
my_operation = MyOperation()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
operations = [my_operation]
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
Migration("name", "app_label").check(),
|
|
||||||
[
|
|
||||||
checks.Error(
|
|
||||||
msg="Support for this operation is gone.",
|
|
||||||
obj=my_operation,
|
|
||||||
hint="Use something else.",
|
|
||||||
id="migrations.E999",
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
|
@ -1,22 +1,11 @@
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
from django.db.migrations.operations.base import Operation
|
|
||||||
|
|
||||||
|
|
||||||
class DummyOperation(Operation):
|
|
||||||
def state_forwards(self, app_label, state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.contrib.postgres.operations import CryptoExtension
|
from django.contrib.postgres.operations import CryptoExtension
|
||||||
except ImportError:
|
except ImportError:
|
||||||
CryptoExtension = DummyOperation
|
CryptoExtension = mock.Mock()
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.db import connection, migrations
|
from django.db import connection, migrations
|
||||||
from django.db.migrations.operations.base import Operation
|
|
||||||
|
|
||||||
|
|
||||||
class DummyOperation(Operation):
|
|
||||||
def state_forwards(self, app_label, state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.contrib.postgres.operations import (
|
from django.contrib.postgres.operations import (
|
||||||
|
@ -26,14 +15,14 @@ try:
|
||||||
UnaccentExtension,
|
UnaccentExtension,
|
||||||
)
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
BloomExtension = DummyOperation
|
BloomExtension = mock.Mock()
|
||||||
BtreeGinExtension = DummyOperation
|
BtreeGinExtension = mock.Mock()
|
||||||
BtreeGistExtension = DummyOperation
|
BtreeGistExtension = mock.Mock()
|
||||||
CITextExtension = DummyOperation
|
CITextExtension = mock.Mock()
|
||||||
CreateExtension = DummyOperation
|
CreateExtension = mock.Mock()
|
||||||
HStoreExtension = DummyOperation
|
HStoreExtension = mock.Mock()
|
||||||
TrigramExtension = DummyOperation
|
TrigramExtension = mock.Mock()
|
||||||
UnaccentExtension = DummyOperation
|
UnaccentExtension = mock.Mock()
|
||||||
needs_crypto_extension = False
|
needs_crypto_extension = False
|
||||||
else:
|
else:
|
||||||
needs_crypto_extension = (
|
needs_crypto_extension = (
|
||||||
|
@ -52,7 +41,7 @@ class Migration(migrations.Migration):
|
||||||
# dash in its name.
|
# dash in its name.
|
||||||
CreateExtension("uuid-ossp"),
|
CreateExtension("uuid-ossp"),
|
||||||
# CryptoExtension is required for RandomUUID() on PostgreSQL < 13.
|
# CryptoExtension is required for RandomUUID() on PostgreSQL < 13.
|
||||||
CryptoExtension() if needs_crypto_extension else DummyOperation(),
|
CryptoExtension() if needs_crypto_extension else mock.Mock(),
|
||||||
HStoreExtension(),
|
HStoreExtension(),
|
||||||
TrigramExtension(),
|
TrigramExtension(),
|
||||||
UnaccentExtension(),
|
UnaccentExtension(),
|
||||||
|
|
Loading…
Reference in New Issue