It is important that app `a` is in alphabetically ordering before app `b`
3. Add both apps to `INSTALLED_APPS`
----
4. Add a model to app `a`:
{{{#!python
from django.db import models
class MyModel(models.Model):
pass
}}}
5. Add a model to app `b`:
{{{#!python
from django.db import models
class MyModel(models.Model):
pass
}}}
6. `python manage.py makemigrations`
----
7. Add a `ForeignKey` from `b.MyModel` to `a.MyModel`
{{{#!python
from django.db import models
class MyModel(models.Model):
a = models.ForeignKey('a.MyModel', null=True)
}}}
8. `python manage.py makemigrations`
----
9. Remove the `ForeignKey` on `b.MyModel` to `a.MyModel`
{{{#!python
from django.db import models
class MyModel(models.Model):
pass
}}}
10. `python manage.py makemigrations`
----
11. Remove `a.MyModel`
12. `python manage.py makemigrations`
----
13. `python manage.py showmigrations --plan -v 3`
{{{
[ ] a.0001_initial
[ ] a.0002_delete_mymodel ... (a.0001_initial)
[ ] b.0001_initial
[ ] b.0002_mymodel_a ... (a.0001_initial, b.0001_initial)
[ ] b.0003_remove_mymodel_a ... (b.0002_mymodel_a)
}}}
14. `$ python manage.py migrate`
{{{
Operations to perform:
Apply all migrations: a, b
Running migrations:
Rendering model states... DONE
Applying a.0001_initial... OK
Applying a.0002_delete_mymodel... OK
Applying b.0001_initial... OK
Applying b.0002_mymodel_a...
}}}
{{{#!python
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/markus/Coding/django/django/core/management/__init__.py",
line 330, in execute_from_command_line
utility.execute()
File "/home/markus/Coding/django/django/core/management/__init__.py",
line 322, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/markus/Coding/django/django/core/management/base.py", line
347, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/markus/Coding/django/django/core/management/base.py", line
398, in execute
output = self.handle(*args, **options)
File
"/home/markus/Coding/django/django/core/management/commands/migrate.py",
line 195, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/home/markus/Coding/django/django/db/migrations/executor.py", line
110, in migrate
self.apply_migration(states[migration], migration, fake=fake,
fake_initial=fake_initial)
File "/home/markus/Coding/django/django/db/migrations/executor.py", line
147, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/markus/Coding/django/django/db/migrations/migration.py",
line 118, in apply
operation.database_forwards(self.app_label, schema_editor, old_state,
project_state)
File
"/home/markus/Coding/django/django/db/migrations/operations/fields.py",
line 62, in database_forwards
field,
File "/home/markus/Coding/django/django/db/backends/sqlite3/schema.py",
line 220, in add_field
self._remake_table(model, create_fields=[field])
File "/home/markus/Coding/django/django/db/backends/sqlite3/schema.py",
line 179, in _remake_table
self.create_model(temp_model)
File "/home/markus/Coding/django/django/db/backends/base/schema.py",
line 231, in create_model
definition, extra_params = self.column_sql(model, field)
File "/home/markus/Coding/django/django/db/backends/base/schema.py",
line 130, in column_sql
db_params = field.db_parameters(connection=self.connection)
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 2052, in db_parameters
return {"type": self.db_type(connection), "check": []}
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 2043, in db_type
rel_field = self.target_field
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 1946, in target_field
return self.foreign_related_fields[0]
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 1704, in foreign_related_fields
return tuple(rhs_field for lhs_field, rhs_field in
self.related_fields)
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 1691, in related_fields
self._related_fields = self.resolve_related_fields()
File "/home/markus/Coding/django/django/db/models/fields/related.py",
line 1676, in resolve_related_fields
raise ValueError('Related model %r cannot be resolved' %
self.remote_field.model)
ValueError: Related model 'a.MyModel' cannot be resolved
}}}
----
The problem is that the migration `a.0002_delete_mymodel` doesn't have any
information that it must be applied after `b.0003_remove_mymodel_a` which
in turn removes any references to `a.MyModel` again.
--
Ticket URL: <https://code.djangoproject.com/ticket/24572>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by MarkusH):
I created a demo project to demonstrate the problem:
https://github.com/MarkusH/django-ticket-
triage/compare/master...ticket24572
--
Ticket URL: <https://code.djangoproject.com/ticket/24572#comment:1>
* stage: Unreviewed => Accepted
Comment:
There's more to this than just the fact that a.2 requires b.3 but b.3 is
not a dependency of a.2. Even if a.2 exists but is not run, the above
error will be thrown when migrating to b.2. Git bisect shows that this
particular error is a regression from
1aa3e09c2043c88a760e8b73fb95dc8f1ffef50e.
Fixing the regressions from that commit at least opens up an easy
workaround that doesn't involve deleting migration files. A simple
`manage.py migrate b` followed by `manage.py migrate a` will work.
--
Ticket URL: <https://code.djangoproject.com/ticket/24572#comment:2>
Comment (by MarkusH):
Actually it is bbbed99f6260a8b3e65cb990e49721b1ce4a441b. Which also makes
way more sense, as this does use `a.2` to generate the initial state right
before each migration that needs to be applied. See
https://github.com/django/django/blob/3e7d9d05ac5efff4e4732c3453c7a8ef502d0ed0/django/db/migrations/executor.py#L65
for details.
--
Ticket URL: <https://code.djangoproject.com/ticket/24572#comment:3>
* cc: apollo13 (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/24572#comment:4>
* cc: shaib (added)
Comment:
The right workaround is to add the dependency manually.
Adding the dependency automatically would require keeping close track of
the dependency at the model and field level.
--
Ticket URL: <https://code.djangoproject.com/ticket/24572#comment:5>