Skip to content

Commit 25bf15c

Browse files
charettesfelixxm
authored andcommitted
Refs #22608 -- Made app_label required when optimizing migrations.
This paved the way for the removal of lot of logic when app_label was not specified.
1 parent 911545d commit 25bf15c

File tree

6 files changed

+48
-36
lines changed

6 files changed

+48
-36
lines changed

django/db/migrations/autodetector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def _optimize_migrations(self):
369369
# Optimize migrations
370370
for app_label, migrations in self.migrations.items():
371371
for migration in migrations:
372-
migration.operations = MigrationOptimizer().optimize(migration.operations, app_label=app_label)
372+
migration.operations = MigrationOptimizer().optimize(migration.operations, app_label)
373373

374374
def check_dependency(self, operation, dependency):
375375
"""

django/db/migrations/operations/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def allow_migrate_model(self, connection_alias, model):
113113

114114
return router.allow_migrate_model(connection_alias, model)
115115

116-
def reduce(self, operation, app_label=None):
116+
def reduce(self, operation, app_label):
117117
"""
118118
Return either a list of operations the actual operation should be
119119
replaced with or a boolean that indicates whether or not the specified

django/db/migrations/operations/fields.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ def references_field(self, model_name, name, app_label=None):
6060
return True
6161
return False
6262

63-
def reduce(self, operation, app_label=None):
63+
def reduce(self, operation, app_label):
6464
return (
65-
super().reduce(operation, app_label=app_label) or
65+
super().reduce(operation, app_label) or
6666
not operation.references_field(self.model_name, self.name, app_label)
6767
)
6868

@@ -122,7 +122,7 @@ def database_backwards(self, app_label, schema_editor, from_state, to_state):
122122
def describe(self):
123123
return "Add field %s to %s" % (self.name, self.model_name)
124124

125-
def reduce(self, operation, app_label=None):
125+
def reduce(self, operation, app_label):
126126
if isinstance(operation, FieldOperation) and self.is_same_field_operation(operation):
127127
if isinstance(operation, AlterField):
128128
return [
@@ -142,7 +142,7 @@ def reduce(self, operation, app_label=None):
142142
field=self.field,
143143
),
144144
]
145-
return super().reduce(operation, app_label=app_label)
145+
return super().reduce(operation, app_label)
146146

147147

148148
class RemoveField(FieldOperation):
@@ -186,11 +186,11 @@ def database_backwards(self, app_label, schema_editor, from_state, to_state):
186186
def describe(self):
187187
return "Remove field %s from %s" % (self.name, self.model_name)
188188

189-
def reduce(self, operation, app_label=None):
189+
def reduce(self, operation, app_label):
190190
from .models import DeleteModel
191191
if isinstance(operation, DeleteModel) and operation.name_lower == self.model_name_lower:
192192
return [operation]
193-
return super().reduce(operation, app_label=app_label)
193+
return super().reduce(operation, app_label)
194194

195195

196196
class AlterField(FieldOperation):
@@ -256,7 +256,7 @@ def database_backwards(self, app_label, schema_editor, from_state, to_state):
256256
def describe(self):
257257
return "Alter field %s on %s" % (self.name, self.model_name)
258258

259-
def reduce(self, operation, app_label=None):
259+
def reduce(self, operation, app_label):
260260
if isinstance(operation, RemoveField) and self.is_same_field_operation(operation):
261261
return [operation]
262262
elif isinstance(operation, RenameField) and self.is_same_field_operation(operation):
@@ -268,7 +268,7 @@ def reduce(self, operation, app_label=None):
268268
field=self.field,
269269
),
270270
]
271-
return super().reduce(operation, app_label=app_label)
271+
return super().reduce(operation, app_label)
272272

273273

274274
class RenameField(FieldOperation):
@@ -382,7 +382,7 @@ def references_field(self, model_name, name, app_label=None):
382382
name.lower() == self.new_name_lower
383383
)
384384

385-
def reduce(self, operation, app_label=None):
385+
def reduce(self, operation, app_label):
386386
if (isinstance(operation, RenameField) and
387387
self.is_same_model_operation(operation) and
388388
self.new_name_lower == operation.old_name_lower):
@@ -396,6 +396,6 @@ def reduce(self, operation, app_label=None):
396396
# Skip `FieldOperation.reduce` as we want to run `references_field`
397397
# against self.new_name.
398398
return (
399-
super(FieldOperation, self).reduce(operation, app_label=app_label) or
399+
super(FieldOperation, self).reduce(operation, app_label) or
400400
not operation.references_field(self.model_name, self.new_name, app_label)
401401
)

django/db/migrations/operations/models.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ def name_lower(self):
3131
def references_model(self, name, app_label=None):
3232
return name.lower() == self.name_lower
3333

34-
def reduce(self, operation, app_label=None):
34+
def reduce(self, operation, app_label):
3535
return (
36-
super().reduce(operation, app_label=app_label) or
36+
super().reduce(operation, app_label) or
3737
not operation.references_model(self.name, app_label)
3838
)
3939

@@ -117,7 +117,7 @@ def references_model(self, name, app_label=None):
117117
return True
118118
return False
119119

120-
def reduce(self, operation, app_label=None):
120+
def reduce(self, operation, app_label):
121121
if (isinstance(operation, DeleteModel) and
122122
self.name_lower == operation.name_lower and
123123
not self.options.get("proxy", False)):
@@ -236,7 +236,7 @@ def reduce(self, operation, app_label=None):
236236
managers=self.managers,
237237
),
238238
]
239-
return super().reduce(operation, app_label=app_label)
239+
return super().reduce(operation, app_label)
240240

241241

242242
class DeleteModel(ModelOperation):
@@ -411,7 +411,7 @@ def references_model(self, name, app_label=None):
411411
def describe(self):
412412
return "Rename model %s to %s" % (self.old_name, self.new_name)
413413

414-
def reduce(self, operation, app_label=None):
414+
def reduce(self, operation, app_label):
415415
if (isinstance(operation, RenameModel) and
416416
self.new_name_lower == operation.old_name_lower):
417417
return [
@@ -423,16 +423,16 @@ def reduce(self, operation, app_label=None):
423423
# Skip `ModelOperation.reduce` as we want to run `references_model`
424424
# against self.new_name.
425425
return (
426-
super(ModelOperation, self).reduce(operation, app_label=app_label) or
426+
super(ModelOperation, self).reduce(operation, app_label) or
427427
not operation.references_model(self.new_name, app_label)
428428
)
429429

430430

431431
class ModelOptionOperation(ModelOperation):
432-
def reduce(self, operation, app_label=None):
432+
def reduce(self, operation, app_label):
433433
if isinstance(operation, (self.__class__, DeleteModel)) and self.name_lower == operation.name_lower:
434434
return [operation]
435-
return super().reduce(operation, app_label=app_label)
435+
return super().reduce(operation, app_label)
436436

437437

438438
class AlterModelTable(ModelOptionOperation):

django/db/migrations/optimizer.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class MigrationOptimizer:
99
nothing.
1010
"""
1111

12-
def optimize(self, operations, app_label=None):
12+
def optimize(self, operations, app_label):
1313
"""
1414
Main optimization entry point. Pass in a list of Operation instances,
1515
get out a new list of Operation instances.
@@ -25,11 +25,10 @@ def optimize(self, operations, app_label=None):
2525
The inner loop is run until the starting list is the same as the result
2626
list, and then the result is returned. This means that operation
2727
optimization must be stable and always return an equal or shorter list.
28-
29-
The app_label argument is optional, but if you pass it you'll get more
30-
efficient optimization.
3128
"""
3229
# Internal tracking variable for test assertions about # of loops
30+
if app_label is None:
31+
raise TypeError('app_label must be a str.')
3332
self._iterations = 0
3433
while True:
3534
result = self.optimize_inner(operations, app_label)
@@ -38,7 +37,7 @@ def optimize(self, operations, app_label=None):
3837
return result
3938
operations = result
4039

41-
def optimize_inner(self, operations, app_label=None):
40+
def optimize_inner(self, operations, app_label):
4241
"""Inner optimization loop."""
4342
new_operations = []
4443
for i, operation in enumerate(operations):

tests/migrations/test_optimizer.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def serialize(self, value):
2323
return serializer_factory(value).serialize()[0]
2424

2525
def assertOptimizesTo(self, operations, expected, exact=None, less_than=None, app_label=None):
26-
result, iterations = self.optimize(operations, app_label)
26+
result, iterations = self.optimize(operations, app_label or 'migrations')
2727
result = [self.serialize(f) for f in result]
2828
expected = [self.serialize(f) for f in expected]
2929
self.assertEqual(expected, result)
@@ -39,6 +39,11 @@ def assertOptimizesTo(self, operations, expected, exact=None, less_than=None, ap
3939
def assertDoesNotOptimize(self, operations, **kwargs):
4040
self.assertOptimizesTo(operations, operations, **kwargs)
4141

42+
def test_none_app_label(self):
43+
optimizer = MigrationOptimizer()
44+
with self.assertRaisesMessage(TypeError, 'app_label must be a str'):
45+
optimizer.optimize([], None)
46+
4247
def test_single(self):
4348
"""
4449
The optimizer does nothing on a single operation,
@@ -212,16 +217,8 @@ def test_optimize_through_create(self):
212217
],
213218
[],
214219
)
215-
# This should not work - FK should block it
216-
self.assertDoesNotOptimize(
217-
[
218-
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
219-
migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]),
220-
migrations.DeleteModel("Foo"),
221-
],
222-
)
223-
# The same operations should be optimized if app_label is specified and
224-
# a FK references a model from the other app.
220+
# Operations should be optimized if the FK references a model from the
221+
# other app.
225222
self.assertOptimizesTo(
226223
[
227224
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
@@ -235,6 +232,13 @@ def test_optimize_through_create(self):
235232
)
236233
# But it shouldn't work if a FK references a model with the same
237234
# app_label.
235+
self.assertDoesNotOptimize(
236+
[
237+
migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]),
238+
migrations.CreateModel('Bar', [('other', models.ForeignKey('Foo', models.CASCADE))]),
239+
migrations.DeleteModel('Foo'),
240+
],
241+
)
238242
self.assertDoesNotOptimize(
239243
[
240244
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
@@ -244,12 +248,20 @@ def test_optimize_through_create(self):
244248
app_label="testapp",
245249
)
246250
# This should not work - bases should block it
251+
self.assertDoesNotOptimize(
252+
[
253+
migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]),
254+
migrations.CreateModel('Bar', [('size', models.IntegerField())], bases=('Foo',)),
255+
migrations.DeleteModel('Foo'),
256+
],
257+
)
247258
self.assertDoesNotOptimize(
248259
[
249260
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
250261
migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo",)),
251262
migrations.DeleteModel("Foo"),
252263
],
264+
app_label='testapp',
253265
)
254266
# The same operations should be optimized if app_label and none of
255267
# bases belong to that app.
@@ -293,6 +305,7 @@ def test_optimize_through_create(self):
293305
('reviewer', models.ForeignKey('test_app.Reviewer', models.CASCADE)),
294306
]),
295307
],
308+
app_label='test_app',
296309
)
297310

298311
def test_create_model_add_field(self):

0 commit comments

Comments
 (0)