My new blog here at www.mostovenko.com

Tuesday, April 17, 2012

Flask - lightweight and awesome. Adding UI and creating first module.(part2)


Creation of the first module and basic UI for our app.


For some reasons i can not imagine how to develop some software withour two things - modular architecture and unit-tests. I like to design loosely coupled architecture, to be able to reuse parts of one app in other. This saves me a lot of time, and gives some esthetic pleasure.
So in this article i will cover:

 1. Blueprints - as a tool for separating flask app into modules.
 2. Creating "Hello-world" module.
 3. Adding some static to antigravity-app (base markup)
 4. Adding templates, connecting them to views.

If you haven't done the first part of my flask tutorials i suggest you to read my previous post and create the basic app structure for this article.


All source code is available on bitbucket.


Blueprints.
Actually i suggest you to get familiar with this article, and only after that - continue to reading this post. I've found it very comfortable to use blueprints in flask apps. As for example, for showing the main principle of adding blueprints modules for antigravity-app i decided to create simple hello_module that will not add any useful feature for project, but will demonstrate the main idea of constructing the app from independent modules via using blueprints.
So lets get started and write some code!
First - we need to add new package to our app. Lets add it and call hello_module. As hello_module will have it's own view - lets add view.py module to it. After that - we must open __init__.py file inside our new hello_module package and add this content:
hello_module/__init__.py
from flask import Blueprint
hello_module = Blueprint("hello_module", __name__, template_folder="templates")
import views

Here we are creating blueprint instance for our module - to be able to import and include it in our app. While creating our blueprint, it is useful to specify template_folder as a parameter in Blueprint constructor,  that will be used for holding templates for module. The template folder is added to the searchpath of templates but with a lower priority than the actual application’s template folder. That way you can easily override templates that a blueprint provides in the actual application.
After creating blueprint instance we need to import our views from views.py module to be able to register them.
The initial content of views.py file must be as follows:
views..py
from flask import render_template
from ..hello_module import hello_module

@hello_module.route('/', methods=["GET", "POST"])
def hello():
    """Methods that returns hello.html"""
    
    return render_template('hello.html')

Here we are importing blueprint instance for having an ability to route our views, as it's our first view-function - let's set it's path to "/". In route method, we are defining path and methods. This function will return the content of "hello.html" file. Let's create our first template in templates folder in hello_module. Just for testing - lets set it's content to this:
hello.html is rendered.

When we have something for displaying - lets test our module. But before we must register it in app instance. Now let's modify our app_factory module:
from flask import Flask

def create_app(config_file):
    """
    Creating app object.
    Parameters:
    @config_file : python module with application settings.
    """
    
    # Main app object initialization block.
    app = Flask(__name__)
    app.config.from_object(config_file)
    
    #Registering modules.
    from antigravity_modules.hello_module import hello_module
    app.register_blueprint(hello_module, url_prefix="/")
    
    return app

Here we see that our hello_module is registered in body of create_app method. Ofcourse, we may provide more flexible way of registering modules, and pass some kind of dictionary of blueprint instances as arguments to create_app function, but for now let's keep it simple, for better understanding what is going on.
Ok, now we can launch our application from the project's root directory by typing command "python manage.py runserver", And now we can see our "hello html is rendered" in browser.

Looks ugly?
You will be right, if you will say that what we have now - is ugly unstyled message in browser, that can't ensure us in power of flask framework. Let's fix this and add some basic markup to our project. I will be using twitter bootstrap framework for UI. I like this framework, it's ideal choice for fast prototyping and not only. So let's download it from this page and extract to our projects static folder. Our static folder must have such structure:
static's folder structure









Now it's time to create our base template file, that will keep basic project's design. Create base.html file in the antigravity-app/templates folder. For the beginning let's add some basic markup to base.html file:

<!DOCTYPE html>
<html>
<head>



    {% block title %}{% endblock %}

</head>
<body>
      
{% block content %}{% endblock %}
</body> </html>

As we see in the first version of basic.html file - there is nothing special. In head section we are including styles. At first bootstrap styles, and after that our style.css. This order is important, because now we have an ability to override some bootstrap styles, that we want to. And also, we are defining two blocks: title and content. Those will be placeholders for our modules.
And now let's modify our hello.html template:

{% extends 'base.html' %}
{%block title %}Hello-module{% endblock %}
{% block content%}
    

Hello_module works!!!

{% endblock %}


Nothing special, but now our app looks like better and has it's own layout. Now we easily may add new modules, they will provide new features, without bringing overweight and complexity to other functional parts.
For now, we have one module that is doing something. I suggest you to add another one module and call it main_module. This module also will not provide some very useful feature, but it will show us how easily we can upgrade our app with new functional parts.
Let's go ahead and create new package in antigravity_modules folder and call it main_module. As our main module also will have it's view - let's also create views.py file and register it as our first hello-module. After registering, my create_app method in app_factory was look like this:
def create_app(config_file):
    """
    Creating app object.
    Parameters:
    @config_file : python module with application settings.
    """
    
    # Main app object initialization block.
    app = Flask(__name__)
    app.config.from_object(config_file)
    
    #Registering modules.
    from antigravity_modules.main_module import main_module
    app.register_blueprint(main_module, url_prefix="/")
    
    from antigravity_modules.hello_module import hello_module
    app.register_blueprint(hello_module, url_prefix="/hello")
    
    return app
As you see i've changed default routing of our app. So now, when user firstly enters our app - he sees the contents of the main page from the main_module.
To make life more funny - I've added one more feature to the main_module - when user enters the site - he sees his IP address - is it's not great?))). The main view-function for main_module/views.py looks like this:
@main_module.route('/')
def main():
    """Main app view"""
    user_ip = request.environ.get('REMOTE_USER')
    user_ip = request.remote_addr
    return render_template('main.html', user_ip=user_ip)
Here we are passing user_ip varriable to template context.
And finally our main_module.html looks like this:

{% extends 'base.html' %}
{% block title %}Main{% endblock %}
{% block content %} 
    <h1>Content of main Module</h1>
<h2>User - {% if user_ip %}{{user_ip}}{%else %} undefined {% endif %}</h2>
{% endblock %}

At the end of this part of tutorial let's modify some lines in our base.html file, to achieve more responsive UI. :
Firstly let's modify our modules nav list:


Ok, thats enough for this tutorial. I hope you've found something useful for you. Later i will cover more interesting aspects of building web apps via using flask framework(database layer, login, restriction of access rules, more advanced template scenarios, RESTful api creation, deploying flask apps and others)
I hope you've got the main idea of modular applications building. All code is available here
Thanks for attention!