#31954: MigrationOptimizer mangles operation order if app name contains 
uppercase
letters
--------------------------------------+---------------------------
               Reporter:  koendewit   |          Owner:  koendewit
                   Type:  Bug         |         Status:  assigned
              Component:  Migrations  |        Version:  3.1
               Severity:  Normal      |       Keywords:
           Triage Stage:  Unreviewed  |      Has patch:  0
    Needs documentation:  0           |    Needs tests:  0
Patch needs improvement:  0           |  Easy pickings:  0
                  UI/UX:  0           |
--------------------------------------+---------------------------
 I am aware that app names are preferably all-lowercase according to
 [https://www.python.org/dev/peps/pep-0008/#package-and-module-names 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 the `INSTALLED_APPS` in `mysite/settings.py`
 * Edit `MyApp/models.py` :
   {{{#!python
   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 for `SubModel` comes before the create
 operation for `BaseModel`, 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`.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31954>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/052.314d4f311f1677b09c020b6813148b05%40djangoproject.com.

Reply via email to