[Django] #31954: MigrationOptimizer mangles operation order if app name contains uppercase letters

23 views
Skip to first unread message

Django

unread,
Aug 27, 2020, 9:05:26 AM8/27/20
to django-...@googlegroups.com
#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.

Django

unread,
Aug 27, 2020, 9:42:21 AM8/27/20
to django-...@googlegroups.com
#31954: MigrationOptimizer mangles operation order if app name contains uppercase
letters
-----------------------------+--------------------------------------
Reporter: Koen De Wit | Owner: (none)
Type: Bug | Status: new
Component: Migrations | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Koen De Wit):

* owner: Koen De Wit => (none)
* status: assigned => new
* has_patch: 0 => 1


--
Ticket URL: <https://code.djangoproject.com/ticket/31954#comment:1>

Django

unread,
Aug 27, 2020, 11:29:19 AM8/27/20
to django-...@googlegroups.com
#31954: MigrationOptimizer mangles operation order if app name contains uppercase
letters.
-----------------------------+---------------------------------------
Reporter: Koen De Wit | Owner: Koen De Wit

Type: Bug | Status: assigned
Component: Migrations | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-----------------------------+---------------------------------------
Changes (by felixxm):

* owner: (none) => Koen De Wit
* status: new => assigned
* needs_tests: 0 => 1
* stage: Unreviewed => Accepted


Comment:

[https://github.com/django/django/pull/13354 PR]

--
Ticket URL: <https://code.djangoproject.com/ticket/31954#comment:2>

Django

unread,
Aug 27, 2020, 1:13:11 PM8/27/20
to django-...@googlegroups.com
#31954: MigrationOptimizer mangles operation order if app name contains uppercase
letters.
-----------------------------+---------------------------------------
Reporter: Koen De Wit | Owner: Koen De Wit
Type: Bug | Status: assigned
Component: Migrations | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+---------------------------------------

Changes (by Koen De Wit):

* needs_tests: 1 => 0


Comment:

Added test: https://github.com/django/django/pull/13354/files

--
Ticket URL: <https://code.djangoproject.com/ticket/31954#comment:3>

Django

unread,
Aug 28, 2020, 7:37:20 AM8/28/20
to django-...@googlegroups.com
#31954: MigrationOptimizer mangles operation order if app name contains uppercase
letters.
-----------------------------+---------------------------------------------

Reporter: Koen De Wit | Owner: Koen De Wit
Type: Bug | Status: assigned
Component: Migrations | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+---------------------------------------------
Changes (by felixxm):

* stage: Accepted => Ready for checkin


--
Ticket URL: <https://code.djangoproject.com/ticket/31954#comment:4>

Django

unread,
Aug 28, 2020, 8:07:55 AM8/28/20
to django-...@googlegroups.com
#31954: MigrationOptimizer mangles operation order if app name contains uppercase
letters.
-----------------------------+---------------------------------------------
Reporter: Koen De Wit | Owner: Koen De Wit
Type: Bug | Status: closed
Component: Migrations | Version: 3.1
Severity: Normal | Resolution: fixed

Keywords: | Triage Stage: Ready for checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+---------------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"4c0b4720b0d5b025bc0ce4149eb501b9dde8c03f" 4c0b472]:
{{{
#!CommitTicketReference repository=""
revision="4c0b4720b0d5b025bc0ce4149eb501b9dde8c03f"
Fixed #31954 -- Fixed migration optimization for MTI model creation with
parent model with mixed case app label.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/31954#comment:5>

Reply all
Reply to author
Forward
0 new messages