Website Revamp to Django CMS

It was long past time to redo my hub site, It had been running Drupal for far too long. I won’t tell you what version. Suffice it to say that the version had been unsupported for quite some time before I finally decommissioned it.

Rather than upgrade to a new version of Drupal, I chose to revamp the site and move to Django CMS.

Drupal has been a high-maintenance thorn in my side for a long time. Back in the day, it was really cool because I could get complex sites up and running fairly quickly. But Drupal’s backward-compatibility policy is non-backward-compatible. That is, with each major version, APIs may change incompatibly, requiring code rewrites. Furthermore, each major version is supported for only two major releases. So version 7.x LTS will be end-of-lifed when version 9 comes out (and we don’t know when that will be).

Invariably, all of my Drupal sites went obsolete. And upgrading them was a whole project in itself. I needed to reacquaint myself with the site’s design, go through all the installed modules, and define or develop a migration path to the new release. I basically had to put the whole thing together again from scratch using a new version of Drupal. This especially includes reviewing and perhaps re-developing any custom code… in PHP (which is a whole other rant). Friends don’t let friends use Drupal.

My hub site is incredibly simple, primarily just a home page with links to other pages, like my blogs and LinkedIn profile. The previous incarnation contained a list of posts I had written, aggregated from different blogs, but that can be added as a version-2 feature. I’ll also want an email contact form, which can be added as a version-1.1 feature. The site further served ancillary content, such a page of downloadable short ebooks, which might be more appropriate for other sites, such as my stories blog, which also needs to be updated— All my sites need to be updated.

I chose Django CMS mostly because my feet have been itching to wade into Python and Django in a bigger way, and this is a good excuse. I also expected (correctly) that Django CMS’s content authoring and plugins would make it quick and easy to implement the site. [1]

But all is not beer and skittles in the land of the Flying Circus. I encountered a number of roadblocks. Even so, I’m very happy with the ease with which the system is coming together.

GitHub contains a copy of the code for the website—sans production data or configuration.

Create skeleton files and modules

The first problem I ran into in setting up my Django CMS project: The one and only (best) way does not always work as well in practice as advertised on the tin. [2]

I decided to use pipenv, because it’s the most recent and modern of the Python environment managers, and it uses Pipfile rather than the older (soon-to-be deprecated?) requirements.txt. But djangocms-installer installs all dependent packages (bypassing pipenv) and creates a requirements.txt along with the skeleton code, next to my nice, neat Pipfile.

What I ended up doing was importing the requirements.txt using pipenv install -r requirements.txt, tweaking the resulting Pipfile to remove djangocms-installer and set my desired version ranges appropriately, then wiping the virtual environment and reinstalling everything from scratch (to make sure it still works).

I was also a little put out that I could not install the latest LTS versions of Django CMS (3.4 LTS) and Django (1.11 LTS) together out of the box. The problem turned out to be in the djangocms-column plugin, which djangocms-installer includes by default. The last released version, from September 2016 (!?), only supports up to Django 1.9 (?!). Django 1.9 has been itself unsupported for over a year.

I was pretty sure I wanted to at least play around with djangocms-column—and it did in the end turn out to be quite useful. After some research, I saw that the plugin does work with Django 1.11, and commits were made to its GitHub repository to add that support, but no new packages were ever released. So I changed the appropriate line in Pipfile to refer directly to the appropriate commit:

djangocms-column = {git = "", ref = "2f0a78cde7f5f34c1c925b649f8e2aa6b2ad8145"}

The above line is just as it appears, long enough to burst through the bounds of any normal editor window. That’s because of the TOML syntax on which Pipfile is based. (But that rant is a different blog post.)

Adding content and theming

Henceforth Django CMS’s beauty begins to shine.

I already knew that Django CMS’s content creation UI would rock. Once I learned my way around the interface, creating content was simple and painless. Even the rich text editor didn’t suck.

I did have some trouble with the way images display. I inserted a row of social media icons, each linked to one of my social media accounts. The generated HTML looks something like this:

    <a href=""
<img src="facebook_icon.png"
    <a …

I’ve cleaned it up a little for clarity. There’s actually a lot of extra whitespace, and the image file is a long path into a folder managed by the filer plugin. But it’s that whitespace that’s at issue. Extra whitespace between HTML tags is significant, as it’s rendered by the browser as an actual space. The extra space inside the hyperlink, inside the <a> tag, appears in the browser as a space with a blue underline next to each icon image. That’s not what I wanted.

It really needs to rendered something like this:

<a href=""
><img src="facebook_icon.png"
></a><a …

I’m pretty sure that this can be addressed via templating, but I’m disappointed that the default template is so obviously broken.

For now, I’ve just hacked the barely-themed default to add a gutter between columns and to include a <meta charset="utf-8"> in the <head>. The former is a bug in the djangocms-column plugin, but the latter is a bug in the stock project template. Sigh.

I also tweaked the template to include the page title at the top of the page, a minimal customization I wanted. I’ll theme it more fully later, as I learn the Django template language.

Version-control and deploying

Django is an enterprise-grade web-development framework, and as such it very easily supports a version-control workflow that we’ve never been able to get to work cleanly with Drupal. I can develop the website on my development machine, commit everything to version control, get everything to work the way I want, and then deploy it in production.

I do have to revise my project’s settings module, as it has site-specific and project-global settings all mixed together by default. In particular, I blanked out SECRET_KEY in the branch that gets pushed to GitHub. In the end, I’ll want to split production settings out into their own module, in order to comply with the Django deployment checklist. It would’ve been nice if the Django skeleton provided stock settings modules to document that process, but I guess it isn’t rocket science.

For now, actually, I’m not even deploying the CMS to production. It’s really just serving up static content, so that’s what I’ve deployed on my server.

  1. python runserver in the project directory.

  2. wget -krp in another window.

  3. Copy the resulting, downloaded directory hierarchy into the server’s docroot, and Bob’s your uncle.

Future releases of the website will include Google Analytics support and caching (maybe), in addition to the other features on my list.

On reflection, this didn’t require much Python development, although I did end up reading a lot of Python code.

I’ll eventually want to renovate all my websites. My dream is to implement all the blogs as a multi-site view on a single headless CMS. Sort of a “Planet Tim.” (And Django might be an appropriate platform for that.)

But for now, I feel like I’ve accomplished something and made it to a low-but-stable rung on the ladder.

[1] Truthfully, this is probably just a diversion on a path to something completely different, probably a static site with select dynamic pages implemented in some technology yet to be determined.

[2] Yes, I’m noticing it, too. I’m using an awful lot of British-isms. I’m not doing it on purpose. It must be the Monty Python vibe, spam and eggs and all that. This might turn out to be a pattern, dropping into lame Americanized British-isms every time I talk about Python programming or anything written in or associated with Python. #SorryNotSorry

This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a reply