1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +00:00

Refs #27236 -- Removed Meta.index_together per deprecation timeline.

This commit is contained in:
Mariusz Felisiak
2023-09-12 05:56:16 +02:00
parent 00e1879610
commit 2abf417c81
25 changed files with 41 additions and 1308 deletions

View File

@@ -13,9 +13,8 @@ from django.db.migrations.graph import MigrationGraph
from django.db.migrations.loader import MigrationLoader
from django.db.migrations.questioner import MigrationQuestioner
from django.db.migrations.state import ModelState, ProjectState
from django.test import SimpleTestCase, TestCase, ignore_warnings, override_settings
from django.test import SimpleTestCase, TestCase, override_settings
from django.test.utils import isolate_lru_cache
from django.utils.deprecation import RemovedInDjango51Warning
from .models import FoodManager, FoodQuerySet
@@ -4872,592 +4871,6 @@ class AutodetectorTests(BaseAutodetectorTests):
self.assertOperationAttributes(changes, "testapp", 0, 0, name="Book")
@ignore_warnings(category=RemovedInDjango51Warning)
class AutodetectorIndexTogetherTests(BaseAutodetectorTests):
book_index_together = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("author", models.ForeignKey("testapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"index_together": {("author", "title")},
},
)
book_index_together_2 = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("author", models.ForeignKey("testapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"index_together": {("title", "author")},
},
)
book_index_together_3 = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("newfield", models.IntegerField()),
("author", models.ForeignKey("testapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"index_together": {("title", "newfield")},
},
)
book_index_together_4 = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("newfield2", models.IntegerField()),
("author", models.ForeignKey("testapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"index_together": {("title", "newfield2")},
},
)
def test_empty_index_together(self):
"""Empty index_together shouldn't generate a migration."""
# Explicitly testing for not specified, since this is the case after
# a CreateModel operation w/o any definition on the original model
model_state_not_specified = ModelState(
"a", "model", [("id", models.AutoField(primary_key=True))]
)
# Explicitly testing for None, since this was the issue in #23452 after
# an AlterIndexTogether operation with e.g. () as value
model_state_none = ModelState(
"a",
"model",
[("id", models.AutoField(primary_key=True))],
{
"index_together": None,
},
)
# Explicitly testing for the empty set, since we now always have sets.
# During removal (('col1', 'col2'),) --> () this becomes set([])
model_state_empty = ModelState(
"a",
"model",
[("id", models.AutoField(primary_key=True))],
{
"index_together": set(),
},
)
def test(from_state, to_state, msg):
changes = self.get_changes([from_state], [to_state])
if changes:
ops = ", ".join(
o.__class__.__name__ for o in changes["a"][0].operations
)
self.fail("Created operation(s) %s from %s" % (ops, msg))
tests = (
(
model_state_not_specified,
model_state_not_specified,
'"not specified" to "not specified"',
),
(model_state_not_specified, model_state_none, '"not specified" to "None"'),
(
model_state_not_specified,
model_state_empty,
'"not specified" to "empty"',
),
(model_state_none, model_state_not_specified, '"None" to "not specified"'),
(model_state_none, model_state_none, '"None" to "None"'),
(model_state_none, model_state_empty, '"None" to "empty"'),
(
model_state_empty,
model_state_not_specified,
'"empty" to "not specified"',
),
(model_state_empty, model_state_none, '"empty" to "None"'),
(model_state_empty, model_state_empty, '"empty" to "empty"'),
)
for t in tests:
test(*t)
def test_rename_index_together_to_index(self):
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, AutodetectorTests.book_indexes],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(changes, "otherapp", 0, ["RenameIndex"])
self.assertOperationAttributes(
changes,
"otherapp",
0,
0,
model_name="book",
new_name="book_title_author_idx",
old_fields=("author", "title"),
)
def test_rename_index_together_to_index_extra_options(self):
# Indexes with extra options don't match indexes in index_together.
book_partial_index = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("author", models.ForeignKey("testapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"indexes": [
models.Index(
fields=["author", "title"],
condition=models.Q(title__startswith="The"),
name="book_title_author_idx",
)
],
},
)
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, book_partial_index],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AlterIndexTogether", "AddIndex"],
)
def test_rename_index_together_to_index_order_fields(self):
# Indexes with reordered fields don't match indexes in index_together.
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, AutodetectorTests.book_unordered_indexes],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AlterIndexTogether", "AddIndex"],
)
def test_add_index_together(self):
changes = self.get_changes(
[AutodetectorTests.author_empty, AutodetectorTests.book],
[AutodetectorTests.author_empty, self.book_index_together],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(changes, "otherapp", 0, ["AlterIndexTogether"])
self.assertOperationAttributes(
changes, "otherapp", 0, 0, name="book", index_together={("author", "title")}
)
def test_remove_index_together(self):
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, AutodetectorTests.book],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(changes, "otherapp", 0, ["AlterIndexTogether"])
self.assertOperationAttributes(
changes, "otherapp", 0, 0, name="book", index_together=set()
)
def test_index_together_remove_fk(self):
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, AutodetectorTests.book_with_no_author],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AlterIndexTogether", "RemoveField"],
)
self.assertOperationAttributes(
changes, "otherapp", 0, 0, name="book", index_together=set()
)
self.assertOperationAttributes(
changes, "otherapp", 0, 1, model_name="book", name="author"
)
def test_index_together_no_changes(self):
"""
index_together doesn't generate a migration if no changes have been
made.
"""
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, self.book_index_together],
)
self.assertEqual(len(changes), 0)
def test_index_together_ordering(self):
"""index_together triggers on ordering changes."""
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together],
[AutodetectorTests.author_empty, self.book_index_together_2],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AlterIndexTogether"],
)
self.assertOperationAttributes(
changes,
"otherapp",
0,
0,
name="book",
index_together={("title", "author")},
)
def test_add_field_and_index_together(self):
"""
Added fields will be created before using them in index_together.
"""
changes = self.get_changes(
[AutodetectorTests.author_empty, AutodetectorTests.book],
[AutodetectorTests.author_empty, self.book_index_together_3],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AddField", "AlterIndexTogether"],
)
self.assertOperationAttributes(
changes,
"otherapp",
0,
1,
name="book",
index_together={("title", "newfield")},
)
def test_create_model_and_index_together(self):
author = ModelState(
"otherapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
],
)
book_with_author = ModelState(
"otherapp",
"Book",
[
("id", models.AutoField(primary_key=True)),
("author", models.ForeignKey("otherapp.Author", models.CASCADE)),
("title", models.CharField(max_length=200)),
],
{
"index_together": {("title", "author")},
},
)
changes = self.get_changes(
[AutodetectorTests.book_with_no_author], [author, book_with_author]
)
self.assertEqual(len(changes["otherapp"]), 1)
migration = changes["otherapp"][0]
self.assertEqual(len(migration.operations), 3)
self.assertOperationTypes(
changes,
"otherapp",
0,
["CreateModel", "AddField", "AlterIndexTogether"],
)
def test_remove_field_and_index_together(self):
"""
Removed fields will be removed after updating index_together.
"""
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together_3],
[AutodetectorTests.author_empty, self.book_index_together],
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["AlterIndexTogether", "RemoveField"],
)
self.assertOperationAttributes(
changes,
"otherapp",
0,
0,
name="book",
index_together={("author", "title")},
)
self.assertOperationAttributes(
changes,
"otherapp",
0,
1,
model_name="book",
name="newfield",
)
def test_alter_field_and_index_together(self):
"""Fields are altered after deleting some index_together."""
initial_author = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("age", models.IntegerField(db_index=True)),
],
{
"index_together": {("name",)},
},
)
author_reversed_constraints = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200, unique=True)),
("age", models.IntegerField()),
],
{
"index_together": {("age",)},
},
)
changes = self.get_changes([initial_author], [author_reversed_constraints])
self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes(
changes,
"testapp",
0,
[
"AlterIndexTogether",
"AlterField",
"AlterField",
"AlterIndexTogether",
],
)
self.assertOperationAttributes(
changes,
"testapp",
0,
0,
name="author",
index_together=set(),
)
self.assertOperationAttributes(
changes,
"testapp",
0,
1,
model_name="author",
name="age",
)
self.assertOperationAttributes(
changes,
"testapp",
0,
2,
model_name="author",
name="name",
)
self.assertOperationAttributes(
changes,
"testapp",
0,
3,
name="author",
index_together={("age",)},
)
def test_partly_alter_index_together_increase(self):
initial_author = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("age", models.IntegerField()),
],
{
"index_together": {("name",)},
},
)
author_new_constraints = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("age", models.IntegerField()),
],
{
"index_together": {("name",), ("age",)},
},
)
changes = self.get_changes([initial_author], [author_new_constraints])
self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes(
changes,
"testapp",
0,
["AlterIndexTogether"],
)
self.assertOperationAttributes(
changes,
"testapp",
0,
0,
name="author",
index_together={("name",), ("age",)},
)
def test_partly_alter_index_together_decrease(self):
initial_author = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("age", models.IntegerField()),
],
{
"index_together": {("name",), ("age",)},
},
)
author_new_constraints = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("age", models.IntegerField()),
],
{
"index_together": {("age",)},
},
)
changes = self.get_changes([initial_author], [author_new_constraints])
self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes(
changes,
"testapp",
0,
["AlterIndexTogether"],
)
self.assertOperationAttributes(
changes,
"testapp",
0,
0,
name="author",
index_together={("age",)},
)
def test_rename_field_and_index_together(self):
"""Fields are renamed before updating index_together."""
changes = self.get_changes(
[AutodetectorTests.author_empty, self.book_index_together_3],
[AutodetectorTests.author_empty, self.book_index_together_4],
MigrationQuestioner({"ask_rename": True}),
)
self.assertNumberMigrations(changes, "otherapp", 1)
self.assertOperationTypes(
changes,
"otherapp",
0,
["RenameField", "AlterIndexTogether"],
)
self.assertOperationAttributes(
changes,
"otherapp",
0,
1,
name="book",
index_together={("title", "newfield2")},
)
def test_add_model_order_with_respect_to_index_together(self):
changes = self.get_changes(
[],
[
AutodetectorTests.book,
ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("book", models.ForeignKey("otherapp.Book", models.CASCADE)),
],
options={
"order_with_respect_to": "book",
"index_together": {("name", "_order")},
},
),
],
)
self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"])
self.assertOperationAttributes(
changes,
"testapp",
0,
0,
name="Author",
options={
"order_with_respect_to": "book",
"index_together": {("name", "_order")},
},
)
def test_set_alter_order_with_respect_to_index_together(self):
after = ModelState(
"testapp",
"Author",
[
("id", models.AutoField(primary_key=True)),
("name", models.CharField(max_length=200)),
("book", models.ForeignKey("otherapp.Book", models.CASCADE)),
],
options={
"order_with_respect_to": "book",
"index_together": {("name", "_order")},
},
)
changes = self.get_changes(
[AutodetectorTests.book, AutodetectorTests.author_with_book],
[AutodetectorTests.book, after],
)
self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes(
changes,
"testapp",
0,
["AlterOrderWithRespectTo", "AlterIndexTogether"],
)
class MigrationSuggestNameTests(SimpleTestCase):
def test_no_operations(self):
class Migration(migrations.Migration):