Flask Biography Tutorial Part IV : Application Layout and Templating Using Bootstrap 3 and Jinja 2

Saviour of the CSS Soulless creature
 Bootstrap is The Saviour for the CSS soulless coder like me.
For the sake of the Lord, quick, get it here!

If you have followed this article until this point, it means that you really curious on how you can develop a working Python web application. Previously we have understand how to create a working (but dumb) Flask application. Today we are going to start by laying out our application user interface using a very cool front-end framework : Bootstrap.

I assess myself as an experience coder but not so good with HTML layout, CSS and Typography. Especially CSS. I am not completely blind with CSS, but trying to design a full scale web application layout from the scratch using plain HTML and CSS, well, is something I already considered as beyond my ability. My ultimate fist in handling CSS is .. Copy & Paste™ ! Laughing 

Thanks to Mark Otto and Jacob Thornton at Twitter, that fist is getting its benefit. They recognized the burden of work and pain of trying to standardized various library and framework used in the user interface development. Starting as an internal project, Bootstrap was developed to tackle those issues. After releasing it as an open source project in Github, in 2012 it was the most popular open source project. You know, I really curious of how many souls that was saved by Bootstrap....

Making Boostrap Starter Template Runnable in Flask

Okay, enough blabbing... 
Let's start the design of our Bio page : The Bootstrap Way. I assume that you have already downloaded Bootstrap 3, extract it and inspect it contents. Open up the folder bootstrap-3.0.0\examples\starter-template, which is a good template for our Bio application. Open up its index.html in a web browser, and you will see this page :

Bootstrap starter template
Bootstrap starter template

Our first task should be to let our Flask application able to display this Bootstrap starter template. Recall from our previous index() method below:

@application.route('/')
def index():
   return "Hello world!" 

To make this method return our template, first we must create wsgi/templates folder, and stored our templates there. Before starting with the Bootstrap Starter Template, try to create the following HTML file instead :

<html>
<head>
<title>My awesome Flask application</title> </head>
<body>
Hello world!
</body> </html>

Saves it in wsgi/templates/hello_world.html file. And make the modification to the file main.py as follow :

from flask import Flask, render_template
application = Flask(__name__)
@application.route('/')
def index():
  return render_template("hello_world.html")
if __name__ == '__main__':
  application.run(debug=True, host="0.0.0.0", port=9999) 

We simply import another method, render_template, from flask package and call it in our index() method to render our simple hello_world.html file. Straightforward, isn't it? But the same case did not applied when you try to render a bootstrap template.

Have a look at the folder bootstrap-3.0.0\examples\starter-template. It contains only two files: index.html and starter-template.css. But if you open index.html, you will see these lines :

<link rel="shortcut icon" href="../../assets/ico/favicon.png">
<link href="../../dist/css/bootstrap.css" rel="stylesheet">
<link href="starter-template.css" rel="stylesheet">
<script src="../../assets/js/jquery.js"></script>
<script src="../../dist/js/bootstrap.min.js"></script>

It means that it refer to external files required by Bootstrap, using static referencing from within your application.

How do you refer to static files from inside your application? I think you may already guessed it: put them under directory wsgi/static and change your index.html code to reflect the new location. We also want our application to have some kind of theme switching mechanism. It will let users able to choose how they display their bio page using themes that we provide or we may also let user upload their own themes. Lets named our first theme : water. Every living things was coming from water, right? Laughing Knows that we only move starter-template.css, which is the only external theme dependant file, to /static/themes/water directory. All the other external files are moved directly beneath /static directory. Inspect the following changes:

<link rel="shortcut icon" href="/static/assets/ico/favicon.png">
<link href="/static/dist/css/bootstrap.css" rel="stylesheet">
<link href="/static/themes/water/starter-template.css" rel="stylesheet">
<script src="/static/assets/js/jquery.js"></script>
<script src="/static/dist/js/bootstrap.min.js"></script>

As for the file bootstrap-3.0.0\examples\starter-template\index.html, we move it to wsgi\templates\themes\water\index.html. Using this directory organization we will have the flexibility of having a themes switching capability in our application.

To render this new Bootstrap Starter Template, change the index() method as follows :

def index():
return render_template("themes/water/index.html")

Building Page Layout

In building our page layout, first we must define what data will be displayed. In our application, we would like to let user biography data to be shown, which are :

  1. Full name
  2. User profile description in short and long format.
  3. Avatar
  4. Product portofolio in a list/table, complete with badge showing technology that it used
  5. And finally, a search bar where user can filter product portofolio by its technology

After a quick prototyping (involving a lot of Copy & Paste™ fists!), I came up with this layout :

Our Bio page prototype using 2 columns layout
Our Bio page prototype using 2 columns layout 

Not bad isn't it?

Most of the idea come from examples\theme folder. It contains just about enough (but not all) visual elements that you can easily Copy & Paste™ when you prototype your application. The search bar is coming from this stackoverflow article. But you can composed it using official components catalog for bootstrap. Try experimenting with different components, creating a completely different page layout. Don't worry, the application already designed to let user choose and switch to any theme for his/her bio page.

The most important concept when you work with Bootstrap, is to understand that it use a 12 columns layout. Have a quick look at our current bio page layout. You can clearly see that it is a two column layout, right? As Boostrap is using a 12 columns layout, we can choose any column combinations as long at it summed up to 12. Here is a snippet of columns layout that I use :

<div class="row">
<div class="col-sm-4">
..
</div>
<div class="col-sm-8">
..
</div>

4 + 8 is equal to 12, right?
So, if you want a larger content for your avatar, you just have to increase col-sm-4 to col-sm-5, and decreasing col-sm-8 to col-sm-7. Very simple, yet it really powerful in helping you laying out your application user interface elements.

Lastly, remember that from my earlier post, I would like each user to have their own Bio page using their username appended to the main application URL. This means the layout above will be for a certain user bio page. We still need another layout for our own home page. Thinking about it quick, I came up with this layout :

Our homepage layout for Bio application.
Our homepage layout for Bio application.

It use Jumbotron for that stand out contents, making it catches our visitor eyes quickly. From within the jumbotron, the most important key content is that blue Signup now! button. It emphasizes that our application is one of the many free services scattered around the web. Trying to give something to the world that already gives us so much...

Utilizing Jinja2 Templating to Implement a Common Layout

Our Flask application is using Jinja2, which is one of the most used templating mechanism in Python world. It lets you generate dynamic content from your template using a simple and intuitive syntax. For example, as you realise that now we have two templates layout, both having a similar design and only differ in certain part, how do you tackle this problem? A simple thinking is to really have two separate files for those two templates. We can named it index.html and bio.html. But you may have an itch in your head by just thinking of it. What if you want to change some common part? Using this two files approach, you have to reflect those changes manually in that two files. Creating a perfectly maintenance nightmare...

Jinja way is very simple. Let's create first a base-layout.html file, which is a common layout for your application. Yes, you may already guess it, that this base-layout.html is actually coming from our wsgi/templates/themes/water/index.html. Rename index.html to base-layout.html, and have a look at the source. Interesting code part are shown below:

<div class="container">
<div class="starter-template">
<h1>Bootstrap starter template</h1>
<p class="lead">Use this document as a way to quickly start any new project.
<br> All you get is this text and a mostly barebones HTML document.</p>
</div>
</div> 

A bootstrap container class functionality is to laying out other bootstrap components. It seems like a perfect placeholder candidate for other template files. So, change it as follows:

<div class="container">
{% block content %}
{% endblock %}
</div> 

We now have a placeholder for a block named content, with data coming from other template files : index.html for our main application page and bio.html for our user biography page.

We use Jinja2 extends mechanism for this.

Let's have a look on our new index.html page:

{% extends "themes/water/base-layout.html" %}
{% block content %}
<div class="jumbotron">
...
...
{% endblock %}

We simply start our index.html page using extends keyword and denote which part of the file that will supply data for block named content. It will greatly simplify your task in template maintenance.

You can also supply any data coming from your Python route/view method to the template file. For example, now that we have  two page : index.html and bio.html, we would like them to have different page title. For the index.html page, we would like to have its page title using our official application name (whatever that is!). While for the bio.html file we would like to have its page title using our user full name. Because both files are using the same layout in the file base-layout.html, it is easy to know where to implement this functionalities. Lets open our base-layout.html and change its <title> element to be as follows:

<head>
..
<title>{{ page_title }}</title>
..
</head>

There, we create a placeholder for a variable named page_title, which we can supply its value from our Python route/view method as follows :

def index():
      return render_template('themes/water/index.html',
page_title = 'Biography just for you!') 

Adjust Route/View Method to Handle Two URL Patterns 

Great!
Now that we already have two page layouts, how do we use this in our Flask application? It's quite simple. Here is the new main.py file shown bellow :

from flask import Flask, render_template
application = Flask(__name__)
@application.route('/')
@application.route('/<username>')
def index(username = None):
   if username is None:
      return render_template('themes/water/index.html', 
page_title = 'Biography just for you!')
   return render_template('themes/water/bio.html', 
page_title = username)
if __name__ == '__main__':
   application.run(debug=True, host="0.0.0.0", port=9999)

Note that our index() method is now having two routes pattern defined for it. We add another responsibility for index() method to respond to url pattern /<username>. If the <username> part is not supplied, which means users try to open our root html address, the method will render themes/water/index.html file. If supplied, which means users try to open a user registered bio page, the method will render themes/water/bio.html. You can also see that we pass page_title variable to the template page to have a different page title for each page.

What's next?

If you have followed series of this articles until this step, it means that now you have a fully working Flask application with templating mechanism using Jinja2. It shows how our final application will look like. Try opening the server address http://localhost:9999 or with any username http://localhost:9999/yourname. You will have the feeling of how the final application should look like. Our next article will look at how we implement the model part of the system. We will define our database model using SQLAlchemy and how we query and present the result to the user. 

You can download archive of this application here : bio-part-4.zip and test it live here : http://bio-ekowibowo.rhcloud.com/. But remember that the live site will always reflect the latest change of the application. So it may not reflect the application progress in this article. For that, you have to download the provided zip file and test/run it locally in your development environment.

I hope you enjoyed this article so far!

Stay tuned! 

 

 




Leave comments

authimage
  • bingung penaruhan filenya, bahasa inggris gw kurang nih -__-. akhirnya download part 4, keluar muka lo pula om.... hahahaha

    • iqbal
  • Hi Crivi,

    Thanks for your compliment :)
    Of course we must install Flask in Openshift. Have your setup.py looks like this https://github.com/pythonthusiast/bio/blob/master/setup.py ?

    The CSS itself (and all static files), must reside in wsgi/static, have a look here : https://github.com/pythonthusiast/bio/tree/master/wsgi/static

    Have fun coding Flask! ;)

    • eko
  • Hi,
    Congrats for this tutorial.
    Since now it works local. but after I deployed it on openShift it doesn*t worked(it look strange the css doesn*t load).
    I think we should install flask on OpenShif
    Have you any idea about this issue.
    Thanks and continue your good job.

    • Crivi

Copyright(c) 2014 - PythonBlogs.com
By using this website, you signify your acceptance of Terms and Conditions and Privacy Policy
All rights reserved