def test_optimize_through_fields(self): """ field-level through checking is working. This should manage to collapse model Foo to nonexistence, and model Bar to a single IntegerField called "width". """ self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.AddField("Foo", "age", models.IntegerField()), migrations.AddField("Bar", "width", models.IntegerField()), migrations.AlterField("Foo", "age", models.IntegerField()), migrations.RenameField("Bar", "size", "dimensions"), migrations.RemoveField("Foo", "age"), migrations.RenameModel("Foo", "Phou"), migrations.RemoveField("Bar", "dimensions"), migrations.RenameModel("Phou", "Fou"), migrations.DeleteModel("Fou"), ], [ migrations.CreateModel("Bar", [("width", models.IntegerField())]), ], )
def test_create_model_reordering_circular_fk(self): """ CreateModel reordering behavior doesn't result in an infinite loop if there are FKs in both directions. """ self.assertOptimizesTo( [ migrations.CreateModel('Bar', [('url', models.TextField())]), migrations.CreateModel( 'Foo', [('name', models.CharField(max_length=255))]), migrations.AddField( 'Bar', 'foo_fk', models.ForeignKey('migrations.Foo', models.CASCADE)), migrations.AddField( 'Foo', 'bar_fk', models.ForeignKey('migrations.Bar', models.CASCADE)), ], [ migrations.CreateModel( 'Foo', [('name', models.CharField(max_length=255))]), migrations.CreateModel('Bar', [ ('url', models.TextField()), ('foo_fk', models.ForeignKey('migrations.Foo', models.CASCADE)), ]), migrations.AddField( 'Foo', 'bar_fk', models.ForeignKey('migrations.Foo', models.CASCADE)), ], )
def test_add_field_alter_field(self): """ AlterField should optimize into AddField. """ self.assertOptimizesTo( [ migrations.AddField("Foo", "age", models.IntegerField()), migrations.AlterField("Foo", "age", models.FloatField(default=2.4)), ], [ migrations.AddField( "Foo", name="age", field=models.FloatField(default=2.4)), ], )
def test_add_field_rename_field(self): """ RenameField should optimize into AddField """ self.assertOptimizesTo( [ migrations.AddField("Foo", "name", models.CharField(max_length=255)), migrations.RenameField("Foo", "name", "title"), ], [ migrations.AddField("Foo", "title", models.CharField(max_length=255)), ], )
class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Project', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], ), migrations.CreateModel( name='Task', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], ), migrations.AddField( model_name='project', name='tasks', field=models.ManyToManyField(to='Task'), ), ]
class Migration(migrations.Migration): initial = True operations = [ migrations.CreateModel( "Author", [ ("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=255)), ("slug", models.SlugField(null=True)), ("age", models.IntegerField(default=0)), ("silly_field", models.BooleanField(default=False)), ], ), migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], ), migrations.AddField( model_name='tribble', name='bool', field=models.BooleanField(default=False), ), migrations.AlterUniqueTogether( name='author', unique_together={('name', 'slug')}, ), ]
def test_create_model_add_field(self): """ AddField should optimize into CreateModel. """ managers = [('objects', EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( name="Foo", fields=[("name", models.CharField(max_length=255))], options={'verbose_name': 'Foo'}, bases=(UnicodeModel, ), managers=managers, ), migrations.AddField("Foo", "age", models.IntegerField()), ], [ migrations.CreateModel( name="Foo", fields=[ ("name", models.CharField(max_length=255)), ("age", models.IntegerField()), ], options={'verbose_name': 'Foo'}, bases=(UnicodeModel, ), managers=managers, ), ], )
def test_add_field_delete_field(self): """ RemoveField should cancel AddField """ self.assertOptimizesTo( [ migrations.AddField("Foo", "age", models.IntegerField()), migrations.RemoveField("Foo", "age"), ], [], )
def test_create_model_no_reordering_for_unrelated_fk(self): """ CreateModel order remains unchanged if the later AddField operation isn't a FK between them. """ self.assertDoesNotOptimize([ migrations.CreateModel( 'Foo', [('name', models.CharField(max_length=255))]), migrations.CreateModel('Link', [('url', models.TextField())]), migrations.AddField( 'Other', 'link', models.ForeignKey('migrations.Link', models.CASCADE)), ], )
class Migration(migrations.Migration): dependencies = [ ('postgres_tests', '0001_initial'), ] operations = [ migrations.AddField( model_name='integerarraydefaultmodel', name='field_2', field=djmodels.contrib.postgres.fields.ArrayField(models.IntegerField(), default=[], size=None), preserve_default=False, ), ]
class Migration(migrations.Migration): initial = True dependencies = [ ("migrations", "0001_initial"), ] operations = [ migrations.AddField( model_name='task', name='projects', field=models.ManyToManyField(to='Project'), ), ]
class Migration(migrations.Migration): dependencies = [("unspecified_app_with_conflict", "0001_initial")] operations = [ migrations.DeleteModel("Tribble"), migrations.RemoveField("Author", "silly_field"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), ], ) ]
class Migration(migrations.Migration): dependencies = [] operations = [ migrations.DeleteModel("Tribble"), migrations.RemoveField("Author", "silly_field"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey( "migrations.Author", models.SET_NULL, null=True)), ], ) ]
def test_sorted_imports(self): """ #24155 - Tests ordering of imports. """ migration = type( "Migration", (migrations.Migration, ), { "operations": [ migrations.AddField( "mymodel", "myfield", models.DateTimeField(default=datetime.datetime( 2012, 1, 1, 1, 1, tzinfo=utc), )), ] }) writer = MigrationWriter(migration) output = writer.as_string() self.assertIn( "import datetime\n" "from djmodels.db import migrations, models\n" "from djmodels.utils.timezone import utc\n", output)
def test_create_model_add_field_not_through_m2m_through(self): """ AddField should NOT optimize into CreateModel if it's an M2M using a through that's created between them. """ self.assertDoesNotOptimize([ migrations.CreateModel('Employee', []), migrations.CreateModel('Employer', []), migrations.CreateModel('Employment', [ ('employee', models.ForeignKey('migrations.Employee', models.CASCADE)), ('employment', models.ForeignKey('migrations.Employer', models.CASCADE)), ]), migrations.AddField( 'Employer', 'employees', models.ManyToManyField( 'migrations.Employee', through='migrations.Employment', )), ], )
class Migration(migrations.Migration): initial = True dependencies = [ ("migrations", "0001_initial"), ] operations = [ migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey( "migrations.Author", models.SET_NULL, null=True)), ], ), ]
def test_simple_migration(self): """ Tests serializing a simple migration. """ fields = { 'charfield': models.DateTimeField(default=datetime.datetime.utcnow), 'datetimefield': models.DateTimeField(default=datetime.datetime.utcnow), } options = { 'verbose_name': 'My model', 'verbose_name_plural': 'My models', } migration = type( "Migration", (migrations.Migration, ), { "operations": [ migrations.CreateModel("MyModel", tuple(fields.items()), options, (models.Model, )), migrations.CreateModel("MyModel2", tuple(fields.items()), bases=(models.Model, )), migrations.CreateModel(name="MyModel3", fields=tuple(fields.items()), options=options, bases=(models.Model, )), migrations.DeleteModel("MyModel"), migrations.AddField("OtherModel", "datetimefield", fields["datetimefield"]), ], "dependencies": [("testapp", "some_other_one")], }) writer = MigrationWriter(migration) output = writer.as_string() # We don't test the output formatting - that's too fragile. # Just make sure it runs for now, and that things look alright. result = self.safe_exec(output) self.assertIn("Migration", result)
def test_create_model_no_reordering_of_inherited_model(self): """ A CreateModel that inherits from another isn't reordered to avoid moving it earlier than its parent CreateModel operation. """ self.assertOptimizesTo( [ migrations.CreateModel( 'Other', [('foo', models.CharField(max_length=255))]), migrations.CreateModel('ParentModel', [ ('bar', models.CharField(max_length=255)) ]), migrations.CreateModel( 'ChildModel', [('baz', models.CharField(max_length=255))], bases=('migrations.parentmodel', ), ), migrations.AddField( 'Other', 'fk', models.ForeignKey('migrations.ChildModel', models.CASCADE)), ], [ migrations.CreateModel('ParentModel', [ ('bar', models.CharField(max_length=255)) ]), migrations.CreateModel( 'ChildModel', [('baz', models.CharField(max_length=255))], bases=('migrations.parentmodel', ), ), migrations.CreateModel('Other', [ ('foo', models.CharField(max_length=255)), ('fk', models.ForeignKey('migrations.ChildModel', models.CASCADE)), ]), ], )
def test_create_model_reordering(self): """ AddField optimizes into CreateModel if it's a FK to a model that's between them (and there's no FK in the other direction), by changing the order of the CreateModel operations. """ self.assertOptimizesTo( [ migrations.CreateModel( 'Foo', [('name', models.CharField(max_length=255))]), migrations.CreateModel('Link', [('url', models.TextField())]), migrations.AddField( 'Foo', 'link', models.ForeignKey('migrations.Link', models.CASCADE)), ], [ migrations.CreateModel('Link', [('url', models.TextField())]), migrations.CreateModel('Foo', [ ('name', models.CharField(max_length=255)), ('link', models.ForeignKey('migrations.Link', models.CASCADE)) ]), ], )
}, bases=(models.Model,), ), migrations.CreateModel( name='Family', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, unique=True)), ], options={ }, bases=(models.Model,), ), migrations.AddField( model_name='household', name='family', field=models.ForeignKey('gis_migrations.Family', models.SET_NULL, blank=True, null=True), preserve_default=True, ) ] if connection.features.supports_raster: ops += [ migrations.CreateModel( name='Heatmap', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, unique=True)), ('rast', models.fields.RasterField(srid=4326)), ], options={ },
def test_optimize_through_create(self): """ We should be able to optimize away create/delete through a create or delete of a different model, but only if the create operation does not mention the model at all. """ # These should work self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Foo"), ], [ migrations.CreateModel("Bar", [("size", models.IntegerField())]), ], ) self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Bar"), migrations.DeleteModel("Foo"), ], [], ) self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Foo"), migrations.DeleteModel("Bar"), ], [], ) # This should not work - FK should block it self.assertDoesNotOptimize([ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [ ("other", models.ForeignKey("testapp.Foo", models.CASCADE)) ]), migrations.DeleteModel("Foo"), ], ) # The same operations should be optimized if app_label is specified and # a FK references a model from the other app. self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [ ("other", models.ForeignKey("testapp.Foo", models.CASCADE)) ]), migrations.DeleteModel("Foo"), ], [ migrations.CreateModel("Bar", [ ("other", models.ForeignKey("testapp.Foo", models.CASCADE)) ]), ], app_label="otherapp", ) # But it shouldn't work if a FK references a model with the same # app_label. self.assertDoesNotOptimize( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [ ("other", models.ForeignKey("testapp.Foo", models.CASCADE)) ]), migrations.DeleteModel("Foo"), ], app_label="testapp", ) # This should not work - bases should block it self.assertDoesNotOptimize([ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )), migrations.DeleteModel("Foo"), ], ) # The same operations should be optimized if app_label and none of # bases belong to that app. self.assertOptimizesTo( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )), migrations.DeleteModel("Foo"), ], [ migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )), ], app_label="otherapp", ) # But it shouldn't work if some of bases belongs to the specified app. self.assertDoesNotOptimize( [ migrations.CreateModel( "Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )), migrations.DeleteModel("Foo"), ], app_label="testapp", ) self.assertOptimizesTo( [ migrations.CreateModel( 'Book', [('name', models.CharField(max_length=255))]), migrations.CreateModel( 'Person', [('name', models.CharField(max_length=255))]), migrations.AddField( 'book', 'author', models.ForeignKey('test_app.Person', models.CASCADE)), migrations.CreateModel('Review', [ ('book', models.ForeignKey('test_app.Book', models.CASCADE)) ]), migrations.CreateModel( 'Reviewer', [('name', models.CharField(max_length=255))]), migrations.AddField( 'review', 'reviewer', models.ForeignKey('test_app.Reviewer', models.CASCADE)), migrations.RemoveField('book', 'author'), migrations.DeleteModel('Person'), ], [ 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)), ]), ], )
def _test_create_alter_foo_field(self, alter): """ CreateModel, AlterFooTogether/AlterOrderWithRespectTo followed by an add/alter/rename field should optimize to CreateModel with options. """ option_value = getattr(alter, alter.option_name) options = {alter.option_name: option_value} # AddField self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ]), alter, migrations.AddField("Foo", "c", models.IntegerField()), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("c", models.IntegerField()), ], options=options), ], ) # AlterField self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ]), alter, migrations.AlterField("Foo", "b", models.CharField(max_length=255)), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.CharField(max_length=255)), ], options=options), ], ) self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("c", models.IntegerField()), ]), alter, migrations.AlterField("Foo", "c", models.CharField(max_length=255)), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("c", models.CharField(max_length=255)), ], options=options), ], ) # RenameField if isinstance(option_value, str): renamed_options = {alter.option_name: 'c'} else: renamed_options = { alter.option_name: { tuple('c' if value == 'b' else value for value in item) for item in option_value } } self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ]), alter, migrations.RenameField("Foo", "b", "c"), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("c", models.IntegerField()), ], options=renamed_options), ], ) self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ]), alter, migrations.RenameField("Foo", "b", "x"), migrations.RenameField("Foo", "x", "c"), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("c", models.IntegerField()), ], options=renamed_options), ], ) self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("c", models.IntegerField()), ]), alter, migrations.RenameField("Foo", "c", "d"), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("d", models.IntegerField()), ], options=options), ], ) # RemoveField if isinstance(option_value, str): removed_options = None else: removed_options = { alter.option_name: { tuple(value for value in item if value != 'b') for item in option_value } } self.assertOptimizesTo([ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ]), alter, migrations.RemoveField("Foo", "b"), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ], options=removed_options), ]) self.assertOptimizesTo( [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ("c", models.IntegerField()), ]), alter, migrations.RemoveField("Foo", "c"), ], [ migrations.CreateModel("Foo", [ ("a", models.IntegerField()), ("b", models.IntegerField()), ], options=options), ], )