Reorganize, restructure, move to content items, add themes, add more languages
After editing marathon I am Ringo Starr: I've got blisters on my fingers!
This post is about editing code, a lot of editing, huge amounts of editing! When you implement much functionality, you notice things that need attention, things that need you to research, how do others do this, what is the plural of certain words, etc. I maintain a todo list and every time I noticed something that needed attention I added it to this list. The list got too big so I decided to stop adding code for a moment and first solve many of these issues. I knew I had to edit a lot.
Move blueprints to blueprints/admin when they are only used by an administrator
I have a structure where all the blueprints are on the same level, in a directory (surprisingly) called 'blueprints'. I decided to move all administrator blueprints into sub-directory 'blueprints/admin'. I also had to do this for the templates, move administrator blueprint templates to 'templates/admin'. A lot of editing.
Move from blog and page models to content item
This was a big issue. This website is a blog but it also has pages. When I started I defined models BlogPost, BlogPostAuthor, BlogPostCategory, BlogPostTag. Then I wanted to have my pages also in the database so I defined Page, PageAuthor, PageCategory, PageTag. But these are almost identical to the BlogPost. So away with this! I moved both to ContentItem, ContentItemAuthor, ContentItemCategory, ContentItemTag. The ContentItem has an attribute content_item_type which tells whether it is a blog post, a page, or something else. I did not invent this, many CMS and blog software manage content this way. Why did I not think of this before? I did but was just trying to make many other things work. Again a lot of editing.
I use Alembic for SQLAlchemy database migrations. It is a wonderful program but sometimes it can get you in very serious trouble. This was also the case here, where I had to remove tables linked to other tables. Alembic returned with messages that it could not remove foreign keys. The problem is that in such a case Alembic already did a lot of things, meaning that after removing a foreign key manually in Mariadb, Alembic started complaining that it wanted to drop tables which were already dropped. I solved this by editing the version file and rerunning 'upgrade head', and editing and rerunning until finally no more errors were found. This is in fact also a warning for every one wanting to use Alembic. When you run into problems then you often are only able to solve them when you have a very good understanding of SQL. Anyway, a lot of editing.
Add support for themes
This website is very much default Bootstrap. It is nice to try some themes and to do this you must remove as much as possible from other stylesheets so that a new theme can take over. I had a style.css which I split into default.css and a custom.css. The first one, default.css, holds the very specific changes from the default Bootstrap theme, these are only a few lines. This file is included only when the default bootstrap.min.css is included. The second one, custom.css, holds non-color styles for WTForms, etc. and must always be included. There are many themes for Bootstrap, I choose to add Bootswatch themes, They come with a MIT license. After adding them I made them selectable from the navigation bar. TRY THIS YOURSELF. Now I can easily check if I forgot to remove styling things. By the way, I still do not like the default Bootstrap heading sizes. Besides this I can only say that this was a lot of editing.
Add more languages
One day I should add more languages and I decided that this was today. I still had to extend the script that communicates with the DeepL API. Anyway, I added some new languages, machine translated using the DeepL API. You can select them on the top right. Not so much editing this time but it felt like a lot of editing.
And then there was ... a bug
There are all the time bugs in my code but after so much editing there comes a time when you want to do something else, programmers know. It appeared that when changing a language, the language selector got a value from the previous selection. Funny ... NOT. I implemented the multilanguage recipe from the Flask website and the problem was in the code that pops the language from first part of the url. I did not take into account that a language change also can be issued by the visitor which is done by doing a request using the current url with the requested language appended. Ok, fixed. Enough editing for today.
And then there was ... another bonus
Before kicking all changes to production I thought I write a post, this post, about my editing marathon. Everything fine until I tried to assign an image to this post. What? But then I remembered skipping this while editing the view file, not now I thought, will do this sometime later. When you build something with Flask, you know the screen: Werkzeug debugger - Traceback (most recent call last). I am happy, more editing at the last moment. Hey, no problem, I will do it. I will edit.
Links / credits
Bootswatch: Free themes for Bootstrap
- Migrating from Bootstrap 4 to Bootstrap 5
- Using Python's pyOpenSSL to verify SSL certificates downloaded from a host
- Why your website canonical name must be 'www' (or 'app' or something else)
- Flask's SERVER_NAME, subdomains and 404 errors
- Flask, Celery, Redis and Docker
- Celery, Redis and the (in)famous email task example
- Using UUIDs instead of Integer Autoincrement Primary Keys with SQLAlchemy and MariaDb
- Flask with multiple forms on a page posted using AJAX and returning a rendered form result
- Two Flask apps, frontend and admin, on one domain using DispatcherMiddleware
- SLQAlchemy dynamic query building and filtering including soft deletes
- SQLAlchemy server-side datetime calculations
- OWASP Zed Attack Proxy (ZAP) security testing