How I built this website and what I learned in the process


In this post I will share my learning experience as I built this website using the Flask web development framework. Just a heads up... this is not tutorial per se. I will not be teaching step-by-step what to do. Instead, I'll be writing from the perspective of a learner. I will share details on the resources I used, and how I solved some of the problems I faced, while learning everything I needed to know. If you are also trying to learn how to do this, I hope what I share here will be helpful.

My initial motivation for creating this website from scratch using Flask actually did not come from a strong desire to build my own site, and my main programming interest is in data analytics, not web development. But I'm getting to the point in my analytics learning journey where I want to learn more about how to build and deploy data dashboards using Python. The deployment part of this involves elements of web development so I thought building a website from scratch would be a good way to learn the basics of web development I would need to do dashboard deployment.

Picking up the basics of web development also has benefits in my work as a recruiter. The better I understand these technologies, the better I can become at matching great engineers with roles they can excel in.

All the code used to build this site can be found in this repository on my GitHub. But, if you really want to learn this stuff, I recommend not cloning this repo and instead just using it as reference if you get well-and-truly stuck. Even then, there is great value in spending the time to try and solve the problems you run into yourself.

Anyways, I have a lot to cover in this post, so let's get into it.

First, an overview of my learning in relation to this project.

What I knew when I started
- Intermediate level Python
- No experience in web development
- Only a very basic understanding of HTML

What I knew by the end
- How to set up the framework of an application using Flask
- A basic understanding of back-end and front-end web development
- The basics of HTML, CSS, and Bootstrap
- How to use the 'Inspect' browser tool to analyze the structure of webpages

How I plan to use what I learned
- Use my new understanding of web development in building data dashboards
- Use my new site to post on topics of interest to me

What I plan to learn next
- How to deploy this website online
- Interactive plotting using Plotly and/or Bokeh
- Building and deploying data dashboards using Dash and/or Streamlit
- Web-scraping using libraries like Beautiful Soup and Selenium
  * My now better understanding of HTML and webpage structure should help with learning this

Why Flask?

As explained above, my main purpose in building this site was to learn the basics of web development, so I did not want to use a platform that did most of the coding for me. That obviously rules out services like Wordpress. I also looked at one other platform option called Pelican that looked interesting, but it seemed to abstract away a lot of coding which again wouldn't give me the opportunity to really learn the nuts and bolts of web development.

The only programming language I know well is Python, and there are two main Python-based web development frameworks to choose from: Flask and Django. I read up on both, and honestly it seemed like kind of a toss-up when it comes to which one to choose. However, I made the choice to use Flask because a number of the articles I read comparing the two described Flask as better for learning the basics of web development which was what I wanted to do. It was comments like the one below, from this site, that led me to choose Flask:

"Flask is a light-weight, extensible framework. If you want to dig more into coding and learn core concepts, Flask helps you understand how each component from the back-end works to get a simple web application up and running."

Perfect, just what I was looking for. 😄

Goal for my website project

Before getting started, I thought about what kind of functionality I wanted to have. This is just a personal site, so I didn't feel like I needed to have functionality for managing users, which simplifies things a lot. Not having to set up functionality for managing users means there is no need to use forms to collect information and a database is not really needed on the back-end either. I suppose I could have learned more had I tried to set all this up, but I decided for my current purposes and learning goals this was more than I needed.

One thing I knew for sure I did want though was the ability to use Markdown to create posts to put up on my site. Using Markdown makes it possible to include things like blockquotes and formatted code blocks, without having to struggle with writing in HTML.

I also wanted my site to be mobile responsive and easy to navigate. And I wanted to be able to include links to my profiles on LinkedIn and Github.

So, basically, my end goal was to have a user-friendly site for my own personal use, on which I could share posts written in Markdown and visitors could easily find my online profiles to connect with me.

Learning the basics of Flask

I went back to one of my favorite Python learning resources, Corey Schafer's tutorials, to learn the basics of Flask. He has a full Flask tutorial series on his website that covers everything you need to know to build an entire full functioning web application using Flask. These tutorials went far beyond what I needed for my modest site so I really only made use of the first two videos but I watched these repeatedly to understand it well.

I also like to have a book to use as a reference when I'm learning a new tool, and for Flask I used Flask Web Development by Miguel Grinberg. This book as well goes far beyond what I needed at this point so I only read the first few chapters. But I read over these chapters multiple times to try and grasp how it works as best I could.

And of course you should always refer to the official documentation for a package as you are using it. If you are just starting out with Flask, you should be able to find everything you need in the Quickstart section.

Additionally, if you are going to use Flask to build anything beyond a simple "Hello World" type page, you also need to learn how to use the Jinja templating engine that is used inside Flask applications to build a cohesive set of pages. I found that the Template Designer Documentation on the Jinja website had everything I needed to understand how to use this. Also, as a side note, I really like Jinja. It's syntax and usage mirrors that of Python, and you can use conditionals and control structures to do a lot of things that you would normally have to use Javascript for. Below I give an example of a problem I had that was solved using Jinja code instead of Javascript. Anything that works like Python and can save me from having to learn Javascript is wonderful in my book. 👍

Using these resources I was able to learn the basics of Flask, and with them I feel I'm well equipped to learn more in the future if I choose to do so.

Building the website

In this section I'll cover the steps I took to build my site. I'll explain how I used different resources and how I solved some of the tougher problems I encountered along the way.

First off, before getting into a project like this, if you don't have any prior experience using virtual environments, I strongly recommend that you take some time to learn how to set up and use them. Having your project isolated in a virtual environment makes your code reproducible for others, and, most importantly for a website project like this, it's necessary if you want to actually deploy it on the web. I personally use conda, but you can use others like venv too. There are plenty of free tutorials out there you can watch to learn about virtual environments.

I built the basic layout of my website using a fair amount of the code provided by Corey Schafer in the notes below his Flask tutorial videos that I mentioned above. However, to get the structure and look I wanted, I had to remove parts I didn't need and make a lot of changes and additions to the code. The thing is I knew very little about HTML and CSS, so at this point I took a bit of a detour to learn this stuff. I found that going through the W3 Schools tutorials was a good way to learn the basics, and from there I just kind of played around a lot with HTML and CSS in my website to practice.

After building the basic layout of my site, I started working on customizing it for my purposes. Mainly I wanted to be able to be create posts using Markdown that included code highlighting, and so I set out to find examples that were similar to what I was trying to set up.

These two short tutorials below both suggested using Flask-FlatPages to enable the kind of functionality I was looking for, and they were of great help to me:

Note that to get code highlighting to work you need to have a package called pygments installed in your environment. Then you can also choose a style for your highlighting, save it in a CSS file, and link to it in your base HTML template. Jeff Yang's tutorial referenced above has a good explanation on how to set this up.

These are the Flatpages configurations that I needed to use to get the functionality I wanted.

FLATPAGES_EXTENSION = '.md'
FLATPAGES_MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite']

However, it was when I was trying to set up these configurations that I encountered my first tough problem that took me quite a while to solve.


Tough Problem #1 - FlatPages configuration not working

As seems to be the case with many problems in programming, at least for me, the solution for this one turned out to be very simple, but FINDING the solution took a very long time.

I was using code suggested in the two tutorials referenced above, but for some reason my configurations were just not getting recognized. I referred to the relevant FlatPages docs and Googled for a long time but just could not find a solution. Finally, after a lot of searching, I found an answer on Stackoverflow that got this to work for me. But I still wanted to know why the code from the tutorials wasn't working. Eventually I tried rearranging the code a bit and discovered that the code from the tutorials worked as long as it was placed in the right order. Neither of the tutorials I was using explained this part clearly, and I think one of them had an error in that part of the code.

So, in the end, I had two ways to get this to work.

Solution 1: use app.config

app = Flask(__name__)

# Configuration settings for FLATPAGES
app.config['FLATPAGES_EXTENSION'] = '.md'
app.config['FLATPAGES_MARKDOWN_EXTENSIONS'] = ['fenced_code', 'codehilite']

# Initialize flatpages
flatpages = FlatPages(app)

Solution 2: use app.config.from_object(__name__)
* Just be sure to define the configuration variables BEFORE calling the configuration method

app = Flask(__name__)

# Configuration settings for FLATPAGES
FLATPAGES_EXTENSION = '.md'
FLATPAGES_MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite']

# Configure from your application python file
app.config.from_object(__name__)

# Initialize flatpages
flatpages = FlatPages(app)

As I understand it, you can also set app configurations from a separate file, and this is probably the preferred way to go if your app is more complex and uses sensitive values like secret keys, but for a simple static site without a database using one of the above methods should suffice.


Once I had the layout and the functionality I wanted set up, I moved on to making some user experience improvements. In particular, I wanted to have a responsive nav bar and footer on my site so users could easily navigate regardless of the kind of device they are using. This kind of stuff is the realm of Bootstrap.

Fortunately, it is pretty easy to add and use Bootstrap. All you have to do is cut and paste the code needed to get Bootstrap components to work from the Quick start section of the docs. You can find the code for all kinds of components on the Bootstrap site. I used Bootstrap version 4.0 for everything because a lot of the tutorials I was referring to used this version. You can also use the more recent 5.0 version, but I would just be careful not to mix up the versions you use in your code.

There are quite a lot of tutorials on YouTube for learning Bootstrap. I liked this one for a quick overview of the basics, and I found the videos in this series helpful too. There are 85 videos in the series, but I only used a few of them when building my nav bar and footer.

Honestly, I didn't learn Bootstrap all that deeply, or HTML / CSS for that matter, just enough to get done what I needed for my site. But I feel like now I've got a decent foundation if I want to do more with this kind of front-end stuff in the future.

Most likely due to the fact that I did not learn this stuff too deeply, I did run into a couple of tough problems in getting my nav bar and footer to work the way I wanted.


Tough Problem #2 - Getting the nav bar active class to work

I chose a pretty simple nav bar from the nav bar components section of the Bootstrap site and cut and pasted the code into the base template for my site. I then changed the hrefs to the ones for the pages on my site, but, upon doing this, when I clicked on the nav items they no longer showed up in bold to indicate the active page. I searched for a long time to find a way to get this to work, but all the solutions I found described ways to solve this problem using Javascript, which I have zero knowledge of... and zero desire to spend time learning.

Finally, I stumbled upon a brilliant question / answer that used Jinja to conditionally add the active class based on the path of the current request. To be able to access the path you have to add request to your flask imports.

from flask import Flask, render_template, url_for, request

Then you can use Jinja logic in the HTML for the nav bar to add the active class to the current page in accordance with the path.

<ul class="navbar-nav">
  {% if request.path == '/' %}
    <li class="nav-item">
      <a class="nav-link active" href="/">Home <span class="sr-only">(current)</span></a>
    </li>
  {% else %}
    <li class="nav-item">
      <a class="nav-link" href="/">Home</a>
    </li>
  {% endif %}
  {% if request.path == '/about' %}
    <li class="nav-item">
      <a class="nav-link active" href="/about">About <span class="sr-only">(current)</span></a>
    </li>
  {% else %}
    <li class="nav-item">
      <a class="nav-link" href="/about">About</a>
    </li>
  {% endif %}
</ul>


Tough Problem #3 - Getting the sticky footer to actually stick

I added the HTML for my sticky footer from this example I found on the Bootstrap site, but it would not adjust to the length of the content on the page, so it wasn't really sticking properly. This kind of Bootstrap example is interesting in that it's simply provided as a working webpage with no additional explantion. You have to use the browser inspection tool to view the code and then cut and paste it. My problem was that I had not used the inspection tool much before so I didn't know where to look to find eveything I needed to make use of the example. So, once again I scoured Stackoverflow looking for solutions and eventually found the answer I needed.

I found out that the reason my code wasn't working was that I hadn't checked in the head part of the example webpage's HTML. In there was a link to some custom CSS that has to be added to get the footer to stick properly.

<!-- Custom styles for this template -->
<link href="sticky-footer.css" rel="stylesheet">

The href links to this page that has the necessary CSS.

After I added this CSS to the custom CSS for my site, it worked.

Although finding the solution to this problem took quite a while, I'm actually glad I encountered it because I learned a lot about how to use the browser inspection tool while searching for answers, and I began using it a lot more from this point on. It really is extremely useful.


Once I had the footer set up, I used Font Awesome icons for my LinkedIn and Github links. The only minor issue I had was with some annoying lines showing up next to my links. All I had to do to get rid of those was to disable the default text decoration on the links.

a.sm-link {
  color: #444444;
  text-decoration: none;
}

Also note that to use Font Awesome you have to first sign up on the website. Then you get a snippet of code to add to your site.

The last little thing I added was enabling the use of emojis in my markdown posts. 😎

Fortunately, I was able to find a Stackoverflow answer that perfectly explained what I wanted to do.

I just had to pip install the emoji package in my environment, then import emoji and add the following code in my application file.

@app.template_filter('emojify')
def emoji_filter(s):
    return emoji.emojize(s, use_aliases=True)

I included 'use_aliases=True' which adds a few more common emoji aliases in addition to those on the unicode.org emoji list.

The code above that uses emoji.emojize is actually a custom Jinja filter. If you are building a website similar to mine that uses Jinja to render posts in a via a template, you are probably already using another Jinja filter called safe on your posts that tells the template engine that it is 'safe' to render the html that is passed through it. To render the emojis, I just had to add the emojify filter, defined in the code above, in front of the safe filter on my posts.

{{ post.html|emojify|safe }}

You can learn more about Jinja filters here.

Well, that just about covers everything I learned while building this site. The only other things I plan to do in the future is add comment sections to my posts (most likely using Disqus) and pagination once I have a larger number of posts.

I truly enjoyed the time I spent on this project and I'm really happy with how much I learned in the process. Flask is great, and I'm looking forward to using to build dashboards and other small apps in the future. And now I have my own custom personal website too. Good stuff.

My next post will cover how I went about deploying this site on the web.