Opened 10 years ago
Closed 4 years ago
#24849 closed Bug (fixed)
Broken squashmigration when model related to another one gets deleted
| Reported by: | Piotr Maliński | Owned by: | nobody |
|---|---|---|---|
| Component: | Migrations | Version: | 1.8 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
I've got a simple example of an broken squashmigration I had in two apps. The problem is that if a model gets deleted, that has relation to other model then the squash will crash as something will want to do some operation on the non-existing model (relation presence is essential, tested on postgres):
Initial:
class Category(models.Model):
title = models.CharField(max_length=100)
class News(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category)
Second migration:
class Category(models.Model):
title = models.CharField(max_length=100)
class NewCategory(models.Model):
title = models.CharField(max_length=100)
class News(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category, blank=True, null=True)
new_category = models.ForeignKey(NewCategory, blank=True, null=True)
Third:
class NewCategory(models.Model):
title = models.CharField(max_length=100)
class News(models.Model):
title = models.CharField(max_length=100)
new_category = models.ForeignKey(NewCategory, blank=True, null=True)
Squash looks like so:
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='News',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
('category', models.ForeignKey(blank=True, to='relateddeleted.Category', null=True)),
],
),
migrations.CreateModel(
name='NewCategory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
],
),
migrations.AddField(
model_name='news',
name='new_category',
field=models.ForeignKey(blank=True, to='relateddeleted.NewCategory', null=True),
),
migrations.RemoveField(
model_name='news',
name='category',
),
migrations.DeleteModel(
name='Category',
),
]
And on a clean database it throws:
Applying relateddeleted.0001_squashed_0003_auto_20150524_2020...Traceback (most recent call last):
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "relateddeleted_category" does not exist
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
utility.execute()
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/__init__.py", line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/commands/test.py", line 30, in run_from_argv
super(Command, self).run_from_argv(argv)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/base.py", line 390, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/commands/test.py", line 74, in execute
super(Command, self).execute(*args, **options)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/base.py", line 441, in execute
output = self.handle(*args, **options)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/commands/test.py", line 90, in handle
failures = test_runner.run_tests(test_labels)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/test/runner.py", line 210, in run_tests
old_config = self.setup_databases()
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/test/runner.py", line 166, in setup_databases
**kwargs
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/test/runner.py", line 370, in setup_databases
serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE", True),
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/base/creation.py", line 368, in create_test_db
test_flush=not keepdb,
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/__init__.py", line 120, in call_command
return command.execute(*args, **defaults)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/base.py", line 441, in execute
output = self.handle(*args, **options)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/core/management/commands/migrate.py", line 221, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/migrations/executor.py", line 110, in migrate
self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/migrations/executor.py", line 147, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/base/schema.py", line 91, in __exit__
self.execute(sql)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/base/schema.py", line 111, in execute
cursor.execute(sql, params)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/utils/six.py", line 658, in reraise
raise value.with_traceback(tb)
File "/home/piotr/devel/envs/migracje/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "relateddeleted_category" does not exist
Change History (5)
comment:1 by , 10 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 10 years ago
Looks totally different. Old FK gets null/blank and new FK gets blank/null from start, then the old one is dropped. Without the need for related_name.
comment:3 by , 10 years ago
comment:4 by , 10 years ago
| Description: | modified (diff) |
|---|
There was a typo in the "Second migration" step in the description: category = models.ForeignKey(NewCategory, ... instead of ForeignKey(Category .... I fixed that and can now reproduce the same traceback you reported as of a76309f007fff6957f39190b06f8a9055f73130f (Django 1.10.dev).
comment:5 by , 4 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
Bisected this one while having a look at the other squashmigrations tickets.
Fixed in b1cbbe926789bcfc2e118c7d7c7a0f30fab5248a. (#25530)
The regression test included appears to cover this case, so I think closing is appropriate. Let me know if anyone disagrees.
I had to add
related_namein step two to avoid a clashing accessor error from the system check error. With that, when I tried to reproduce this, I got the following squashed migration:operations = [ migrations.CreateModel( name='News', fields=[ ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), ('title', models.CharField(max_length=100)), ('category', models.ForeignKey(blank=True, null=True, to='squash.NewCategory', related_name='foo')), ], ), migrations.CreateModel( name='NewCategory', fields=[ ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), ('title', models.CharField(max_length=100)), ], ), migrations.AddField( model_name='news', name='new_category', field=models.ForeignKey(blank=True, null=True, to='squash.NewCategory'), ), migrations.RemoveField( model_name='news', name='category', ), ]This has the problem that
NewCategoryis created after it's used in theForeignKeywhich results inValueError: Related model 'squash.NewCategory' cannot be resolvedwhen migrating. Accepting at least on that basis.