Opened 4 years ago
Closed 4 years ago
#31954 closed Bug (fixed)
MigrationOptimizer mangles operation order if app name contains uppercase letters.
Reported by: | Koen De Wit | Owned by: | Koen De Wit |
---|---|---|---|
Component: | Migrations | Version: | 3.1 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I am aware that app names are preferably all-lowercase according to PEP 8, but uppercase letters are nevertheless valid.
Steps to reproduce:
- Create a new project and an app with uppercase letters in the app name :
django-admin startproject mysite cd mysite python manage.py startapp MyApp
- Add
'MyApp'
to theINSTALLED_APPS
inmysite/settings.py
- Edit
MyApp/models.py
:from django.db import models class RefModel(models.Model): pass class BaseModel(models.Model): r = models.ForeignKey(RefModel, on_delete=models.PROTECT) class SubModel(BaseModel): pass
- Run
python ./manage.py makemigrations
. In the resulting migration file, the create operation forSubModel
comes before the create operation forBaseModel
, which is wrong. - Run
python ./manage.py migrate
, which will fail with this error:Operations to perform: Apply all migrations: MyApp, admin, auth, contenttypes, sessions Running migrations: Applying MyApp.0001_initial...Traceback (most recent call last): File "./manage.py", line 22, in <module> main() File "./manage.py", line 18, in main execute_from_command_line(sys.argv) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line utility.execute() File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv self.execute(*args, **cmd_options) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute output = self.handle(*args, **options) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/base.py", line 85, in wrapped res = handle_func(*args, **kwargs) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 243, in handle post_migrate_state = executor.migrate( File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/executor.py", line 117, in migrate state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/executor.py", line 227, in apply_migration state = migration.apply(state, schema_editor) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/migration.py", line 114, in apply operation.state_forwards(self.app_label, project_state) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/operations/models.py", line 80, in state_forwards state.add_model(ModelState( File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/state.py", line 95, in add_model self.reload_model(app_label, model_name) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/state.py", line 156, in reload_model self._reload(related_models) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/state.py", line 189, in _reload self.apps.render_multiple(states_to_be_rendered) File "/home/koen/.virtualenvs/dtest/lib/python3.8/site-packages/django/db/migrations/state.py", line 310, in render_multiple raise InvalidBasesError( django.db.migrations.exceptions.InvalidBasesError: Cannot resolve bases for [<ModelState: 'MyApp.SubModel'>] This can happen if you are inheriting models from an app with migrations (e.g. contrib.auth) in an app with no migrations; see https://docs.djangoproject.com/en/3.1/topics/migrations/#dependencies for more
This bug does not occur if the app name is all-lowercase.
Digging into the code, I found that the MigrationOptimizer will combine two operations (Create model BaseModel
and add ForeignKey-field r
to BaseModel
) without taking into account that SubModel
depends on BaseModel
.
Change History (5)
comment:1 by , 4 years ago
Has patch: | set |
---|---|
Owner: | removed |
Status: | assigned → new |
comment:2 by , 4 years ago
Needs tests: | set |
---|---|
Owner: | set to |
Status: | new → assigned |
Summary: | MigrationOptimizer mangles operation order if app name contains uppercase letters → MigrationOptimizer mangles operation order if app name contains uppercase letters. |
Triage Stage: | Unreviewed → Accepted |
comment:3 by , 4 years ago
Needs tests: | unset |
---|
comment:4 by , 4 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
Note:
See TracTickets
for help on using tickets.
PR