Opened 6 years ago

Closed 6 years ago

#25931 closed Bug (fixed)

ContentTypes population doesn't work with backwards migrations

Reported by: Amos Onn Owned by: nobody
Component: contrib.contenttypes Version: 1.9
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

ContentTypes are populated after running ./manage.py migrate. However, the population is run as a post-migration hook, and is unaware of the model state after the migration. Instead, it populates according to the model state as it appears in the code, introducing stale types and suggesting removal of live ones (from the migration's point of view).

Bug 1: When populating a new model and a GFK to it, after migrating to before the creation of that model, the model itself will be removed, but the CT not, and thus the GFK will be broken. When checking out the old code (which matches the database state after the backwards migration), enumerating and going through these GFKs will break.
In the sample project below, run the following to see breakage (make sure to delete db.sqlite3 first):

git checkout master
./manage.py migrate
./populate1.py
./print_wrappers.py
git checkout bug1
./manage.py migrate
./print_wrappers.py
./populate2.py
./print_wrappers.py
./manage.py migrate myapp 0001 # backwards
git checkout master # now code and db should be in sync
./print_cts.py # note that CT of Second is there.
./print_wrappers.py

(sorta) Bug 2: When deleting a model, after migrating to before the deletion of that model, the table will be created but not the contenttype. This does not break anything, because as soon as a GFK using this CT is created, either in the old code or during the migration, the relevant CT is found to be missing and is created on the fly; still, this is a cover-up, and the CT should be generated at the end of the migration.
In the sample project below, run the following to see the missing CT (make sure to delete db.sqlite3 first):

git checkout master
./manage.py migrate
./populate1.py
./print_wrappers.py
git checkout bug2
./manage.py migrate # choose 'yes'; if you choose 'no', the next line will break
./print_wrappers.py
./manage.py migrate myapp 0001 # backwards
git checkout master # now code and db should be in sync
./print_wrappers.py
./print_cts.py # note that CT of First is missing.
./populate1.py # this doesn't break because of the cover-up get_or_create.
./print_cts.py # now CT of First is there.
./print_wrappers.py

The sample project demonstrating both bugs is at:
https://github.com/amosonn/check_ct_populate

Change History (2)

comment:1 Changed 6 years ago by Tim Graham

Triage Stage: UnreviewedAccepted

This is related to #24100 and the tickets mentioned there, and also #24865 which suggests removing content type deletion from the post_migrate() signal which should make things a bit safer. I'll accept this ticket, though I'm not sure what exactly the remaining work will be (if any) after those other tickets are resolved.

comment:2 Changed 6 years ago by Tim Graham

Resolution: fixed
Status: newclosed

I believe this is fixed in Django 1.10 due to #24075. After ./manage.py migrate myapp 0001 # backwards in bug1, you'll now get a prompt to delete stale content types. In bug 2, at ./print_cts.py # note that CT of First is missing. - CT of first is no longer missing.

Note: See TracTickets for help on using tickets.
Back to Top