How to do it...

Have a look at the following layout:

flask_app/ 
    - run.py 
    my_app/ 
        - __init__.py 
        - product/ 
            - __init__.py 
            - views.py 
            - models.py 
        - templates/ 
            - base.html 
            - home.html 
            - product.html 
        - static/ 
            - js/ 
                - bootstrap.min.js 
            - css/ 
                - bootstrap.min.css 
                - main.css 

In the preceding layout, static/css/bootstrap.min.css and static/js/bootstrap.min.js are standard files that can be downloaded from the Bootstrap website mentioned in the Getting ready section. The run.py file remains the same, as always. The rest of the application building process is as follows:

First, define the models in my_app/product/models.py. In this chapter, we will work on a simple, non-persistent key-value store. We will start with a few hardcoded product records made well in advance, as follows:

PRODUCTS = { 
    'iphone': { 
        'name': 'iPhone 5S', 
        'category': 'Phones', 
        'price': 699, 
    },  
    'galaxy': { 
        'name': 'Samsung Galaxy 5', 
        'category': 'Phones', 
        'price': 649, 
    }, 
    'ipad-air': { 
        'name': 'iPad Air', 
        'category': 'Tablets', 
        'price': 649, 
    }, 
    'ipad-mini': { 
        'name': 'iPad Mini', 
        'category': 'Tablets', 
        'price': 549 
    } 
} 

Next comes the views, that is, my_app/product/views.py. Here, we will follow the blueprint style to write the application, as follows:

from werkzeug import abort 
from flask import render_template 
from flask import Blueprint 
from my_app.product.models import PRODUCTS 
 
product_blueprint = Blueprint('product', __name__) 
 
@product_blueprint.route('/') 
@product_blueprint.route('/home') 
def home(): 
    return render_template('home.html', products=PRODUCTS) 
 
@product_blueprint.route('/product/<key>') 
def product(key): 
    product = PRODUCTS.get(key) 
    if not product: 
        abort(404) 
    return render_template('product.html', product=product) 

The name of the blueprint (product) that is passed in the Blueprint constructor will be appended to the endpoints defined in this blueprint. Have a look at the base.html code for clarity.

The abort() method comes in handy when you want to abort a request with a specific error message. Flask provides basic error message pages that can be customized as needed. We will look at them in the Creating custom 404 and 500 handlers recipe in Chapter 4, Working with Views.

Now, create the application's configuration file, my_app/__init__.py, which should look like the following lines of code:

from flask import Flask 
from my_app.product.views import product_blueprint 
 
app = Flask(__name__) 
app.register_blueprint(product_blueprint) 

As well as the CSS code provided by Bootstrap, add a bit of custom CSS code in my_app/static/css/main.css, as follows:

body { 
  padding-top: 50px; 
} 
.top-pad { 
  padding: 40px 15px; 
  text-align: center; 
} 

When considering templates, remember that the first template acts as the base for all templates. Name this template base.html and place it in my_app/templates/base.html, as follows:

<!DOCTYPE html> 
<html lang="en"> 
  <head> 
    <meta charset="utf-8"> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
    <meta name="viewport" content="width=device-width, initial-
scale=1"> <title>Flask Framework Cookbook</title> <link href="{{ url_for('static',
filename='css/bootstrap.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/main.css') }}"
rel="stylesheet"> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"
role="navigation"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="{{ url_for('product.home')
}}">Flask Cookbook</a> </div> </div> </div> <div class="container"> {% block container %}{% endblock %} </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/
2.0.0/jquery.min.js"></script> <script src="{{ url_for('static', filename='js/
bootstrap.min.js') }}"></script> </body> </html>

Most of the preceding code contains normal HTML and Jinja2 evaluation placeholders, which we introduced in the previous chapter. An important point to note, however, is how the url_for() method is used for blueprint URLs. The blueprint name is appended to all endpoints. This becomes very useful when there are multiple blueprints inside one application, as some of them may have similar looking URLs.

On the home page, my_app/templates/home.html, iterate over all the products and display them, as follows:

{% extends 'base.html' %} 
 
{% block container %} 
  <div class="top-pad"> 
    {% for id, product in products.items() %} 
      <div class="well"> 
        <h2> 
          <a href="{{ url_for('product.product', key=id) }}">{{ 
product['name'] }}</a> <small>$ {{ product['price'] }}</small> </h2> </div> {% endfor %} </div> {% endblock %}

Then, create the individual product page, my_app/templates/product.html, which should look like the following lines of code:

{% extends 'home.html' %} 
 
{% block container %} 
  <div class="top-pad"> 
    <h1>{{ product['name'] }} 
      <small>{{ product['category'] }}</small> 
    </h1> 
    <h3>$ {{ product['price'] }}</h3> 
  </div> 
{% endblock %}