“# upgrading to 3.5.x breaks CMS page views”
“# upgrading breaks "manage.py"
“# where is this used?”
“# error on upgrading to 2.1.0”
--- comments in requirements.txt
“Migration 0020_old_tree_cleanup is not reversible.”
--- ./manage.py migrate cms 0016
A Django 1.11 -> 2.2 upgrade did not seem to be a particularly daunting task until I started to read the requirements file. The prospect of fiddling around with package versions, forking deprecated projects, culling unused imports, and manually migrating data, seemed like an inevitability. Through the use of the Poetry project, incremental database changes, and a little luck, the upgrade was completed, but not without its frustrations.
The largest hurdle was the django CMS 3.4 -> 3.7 upgrade, which could be put off no longer, due to its lack of support under Django 2.2. This version bump contained an irreversible migration, which made back-tracking a bit of a pain. Because of this, I created a new copy of the database for each intermediate version bump:
db_cms_34 -> db_cms_35 -> db_cms_36 -> db_cms_37
This allowed me, in effect, to roll back migrations. These incremental databases were important because, without them, the entire update process would have to start back at square one.
The release notes for the django CMS upgrades must be read carefully. They advised that
python manage.py cms fix-tree be run prior to upgrading to a new version. I was presented with several mysterious exceptions, which disappeared after I started heeding the aforementioned directive.
Another potential hurdle was replacing the deprecated
cmsplugin-filer package, which was deprecated after django CMS 3.4. The repo's README.rst file suggested either using a fork of the project or migrating the data over to the
djangocms_filer project. I went with the forked
cmsplugin_filer project and it worked without any issue.
During a major version bump, you can expect your
requirements.txt file to undergo some major changes. In the past, I would fiddle around with versions, run the site, see if any errors popped up, and on and on. For this upgrade I used the Poetry project. Poetry's tag is "Python packaging and dependency management made easy," which turned out to be true. After creating Poetry's version of a requirements file (
poetry.lock) you can run the command:
and Poetry will attempt to find compatible versions of all your dependencies for the pinned versions of your major packages, which in this case were Django ending at 2.2, and django CMS 3.7. Poetry allows you to output your
poetry.lock file as a
requirements.txt, which for reasons unimportant to this post, I decided to use.
poetry export -f requirements.txt > <output file name>.txt
Just like with the databases, I would create a new requirements file for each version bump:
and so on up to Django 2.2 and Django CMS 3.7
Even with this slow and steady approach, aided by modern dependency management tools such as Poetry, this upgrade was a hassle. Several corrupt database records created mysterious exceptions, which required spelunking into the nether regions of the source code to unveil their origin. One such error:
RuntimeError: Unable to render cms menu. There is a language misconfiguration
The solution, which was not obvious to me, was to ensure that all Page's associated Titles had the same value for
Another corrupt record was causing a migration error:
django.db.utils.IntegrityError: column "node_id" contains null
The offending records were only identified after putting a breakpoint in the CMS migration and inspecting the records.
After all was said and done, I learned the value of 1.) making use of modern tools such as Poetry, and 2.) to make slow and steady changes, and saving the state along the way. I hope that this blog will reach someone facing a similar upgrade, and that it will, in any way, help.