Add AlterIndexTogether operation

This commit is contained in:
Andrew Godwin 2013-07-02 18:02:01 +01:00
parent 2202e3f7d3
commit 61ff46cf8b
3 changed files with 67 additions and 2 deletions

View File

@ -1,2 +1,2 @@
from .models import CreateModel, DeleteModel, AlterModelTable, AlterUniqueTogether from .models import CreateModel, DeleteModel, AlterModelTable, AlterUniqueTogether, AlterIndexTogether
from .fields import AddField, RemoveField, AlterField, RenameField from .fields import AddField, RemoveField, AlterField, RenameField

View File

@ -82,7 +82,7 @@ class AlterModelTable(Operation):
class AlterUniqueTogether(Operation): class AlterUniqueTogether(Operation):
""" """
Changes the value of unique_together to the target one. Changes the value of index_together to the target one.
Input value of unique_together must be a set of tuples. Input value of unique_together must be a set of tuples.
""" """
@ -108,3 +108,33 @@ class AlterUniqueTogether(Operation):
def describe(self): def describe(self):
return "Alter unique_together for %s (%s constraints)" % (self.name, len(self.unique_together)) return "Alter unique_together for %s (%s constraints)" % (self.name, len(self.unique_together))
class AlterIndexTogether(Operation):
"""
Changes the value of index_together to the target one.
Input value of index_together must be a set of tuples.
"""
def __init__(self, name, index_together):
self.name = name.lower()
self.index_together = set(tuple(cons) for cons in index_together)
def state_forwards(self, app_label, state):
model_state = state.models[app_label, self.name.lower()]
model_state.options["index_together"] = self.index_together
def database_forwards(self, app_label, schema_editor, from_state, to_state):
old_app_cache = from_state.render()
new_app_cache = to_state.render()
schema_editor.alter_index_together(
new_app_cache.get_model(app_label, self.name),
getattr(old_app_cache.get_model(app_label, self.name)._meta, "index_together", set()),
getattr(new_app_cache.get_model(app_label, self.name)._meta, "index_together", set()),
)
def database_backwards(self, app_label, schema_editor, from_state, to_state):
return self.database_forwards(app_label, schema_editor, from_state, to_state)
def describe(self):
return "Alter index_together for %s (%s constraints)" % (self.name, len(self.index_together))

View File

@ -30,6 +30,19 @@ class OperationTests(TestCase):
def assertColumnNotNull(self, table, column): def assertColumnNotNull(self, table, column):
self.assertEqual([c.null_ok for c in connection.introspection.get_table_description(connection.cursor(), table) if c.name == column][0], False) self.assertEqual([c.null_ok for c in connection.introspection.get_table_description(connection.cursor(), table) if c.name == column][0], False)
def assertIndexExists(self, table, columns, value=True):
self.assertEqual(
value,
any(
c["index"]
for c in connection.introspection.get_constraints(connection.cursor(), table).values()
if c['columns'] == list(columns)
),
)
def assertIndexNotExists(self, table, columns):
return self.assertIndexExists(table, columns, False)
def set_up_test_model(self, app_label): def set_up_test_model(self, app_label):
""" """
Creates a test model state and database table. Creates a test model state and database table.
@ -242,3 +255,25 @@ class OperationTests(TestCase):
cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (1, 1, 1)") cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (1, 1, 1)")
cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)") cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)")
cursor.execute("DELETE FROM test_alunto_pony") cursor.execute("DELETE FROM test_alunto_pony")
def test_alter_index_together(self):
"""
Tests the AlterIndexTogether operation.
"""
project_state = self.set_up_test_model("test_alinto")
# Test the state alteration
operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")])
new_state = project_state.clone()
operation.state_forwards("test_alinto", new_state)
self.assertEqual(len(project_state.models["test_alinto", "pony"].options.get("index_together", set())), 0)
self.assertEqual(len(new_state.models["test_alinto", "pony"].options.get("index_together", set())), 1)
# Make sure there's no matching index
self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])
# Test the database alteration
with connection.schema_editor() as editor:
operation.database_forwards("test_alinto", editor, project_state, new_state)
self.assertIndexExists("test_alinto_pony", ["pink", "weight"])
# And test reversal
with connection.schema_editor() as editor:
operation.database_backwards("test_alinto", editor, new_state, project_state)
self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])