Fixed #27845 -- Allowed both right and left optimizations of operations.

Thanks Raphael Gaschignard for the suggestion.
This commit is contained in:
Simon Charette 2017-02-18 00:55:13 -05:00 committed by Tim Graham
parent 0025dd5eb4
commit 37cafbfb79
2 changed files with 17 additions and 17 deletions

View File

@ -42,21 +42,29 @@ class MigrationOptimizer:
"""Inner optimization loop."""
new_operations = []
for i, operation in enumerate(operations):
right = True # Should we reduce on the right or on the left.
# Compare it to each operation after it
for j, other in enumerate(operations[i + 1:]):
in_between = operations[i + 1:i + j + 1]
result = operation.reduce(other, in_between, app_label)
if isinstance(result, list):
# Add operations optimized through, optimized operations,
# and the remaining ones.
if right:
new_operations.extend(in_between)
new_operations.extend(result)
new_operations.extend(operations[i + j + 2:])
return new_operations
if not result:
# We can't optimize across `other`.
elif all(op.reduce(other, [], app_label) is True for op in in_between):
# Perform a left reduction if all of the in-between
# operations can optimize through other.
new_operations.extend(result)
new_operations.extend(in_between)
else:
# Otherwise keep trying.
new_operations.append(operation)
break
new_operations.extend(operations[i + j + 2:])
return new_operations
elif not result:
# Can't perform a right reduction.
right = False
else:
new_operations.append(operation)
return new_operations

View File

@ -270,8 +270,6 @@ class OptimizerTests(SimpleTestCase):
app_label="testapp",
)
# This could be optimized a bit more but it generates a valid set of
# operations.
self.assertOptimizesTo(
[
migrations.CreateModel('Book', [('name', models.CharField(max_length=255))]),
@ -284,18 +282,12 @@ class OptimizerTests(SimpleTestCase):
migrations.DeleteModel('Person'),
],
[
migrations.CreateModel('Person', [('name', models.CharField(max_length=255))]),
migrations.CreateModel('Book', [
('name', models.CharField(max_length=255)),
('author', models.ForeignKey('test_app.Person', models.CASCADE)),
]),
migrations.CreateModel('Book', [('name', models.CharField(max_length=255))]),
migrations.CreateModel('Reviewer', [('name', models.CharField(max_length=255))]),
migrations.CreateModel('Review', [
('book', models.ForeignKey('test_app.Book', models.CASCADE)),
('reviewer', models.ForeignKey('test_app.Reviewer', models.CASCADE)),
]),
migrations.RemoveField('book', 'author'),
migrations.DeleteModel('Person'),
],
)