coreyShafer

2 - Python Flask Tutorial: Full-Featured Web App Part 2 - Templates

Part 1 - return full html (Templates)

01

We use ''' ''' triple quotes to return multiple lines of htmm

from flask import Flask
app = Flask(__name__)
@app.route('/')
@app.route('/home')
def home():
    return ''' 
    <h1>Home</h1>
    <p> Lorem ipsum dolor sit amet consectetur adipisicing elit...</p>
    '''	
@app.route('/about')
def about():
    return '<h1>About</h1>'

if __name__ == '__main__':
    app.run(debug=True)

But this will get ugly fast

02

We can use templates by creating a templates folder within our directory. Create a htm or html file for both home and about

You have to save html files in directory named "templates"

Other wise it will NOT work

03

Now import render_template function from flask and use the render_template function in the return

    from flask import Flask, render_template
    app = Flask(__name__)
    @app.route('/')
    @app.route('/home')
    def home():
        return render_template('home.htm')

    if __name__ == '__main__':
        app.run(debug=True)

Do the same thing for the about page

Part 2 - using python data in HTML (dummy data)

01

We can place python data into the html as a second argument to render_template

Then use {% for post in posts %} and {% endfor %}.

from flask import Flask, render_template
app = Flask(__name__)

posts = [{
        'author': 'Corey Schafer',
        'title': 'Blog Post 1',
        'content': 'First post content',
        'date_posted': 'April 20, 2018'
    },
    {
        'author': 'Jane Doe',
        'title': 'Blog Post 2',
        'content': 'Second post content',
        'date_posted': 'April 21, 2018'
    }
]

@app.route('/')
@app.route('/home')
def home():
    return render_template('home.htm', posts=posts )
@app.route('/about')
def about():
    return '<h1>About</h1>'

if __name__ == '__main__':
    app.run(debug=True)

02

Now in the HTML do the following to use it

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
</head>
<body>
<h1>Home (rendered)</h1>
{% for post in posts%}
    <h1> {{ post.title }} </h1>
    <p> By {{ post.author }} on {{ post.data_posted }} </p>
    <p> {{ post.content }} </p>
{% endfor %}
</body>
</html>             

Part 3 - {% if title %}

01

We can use if conditionals, for example with the title, we can pass in another variable into render_template,

from flask import Flask, render_template
app = Flask(__name__)

posts = [
    {
        'author': 'Corey Schafer',
        'title': 'Blog Post 1',
        'content': 'First post content',
        'date_posted': 'April 20, 2018'
    },
    {
        'author': 'Jane Doe',
        'title': 'Blog Post 2',
        'content': 'Second post content',
        'date_posted': 'April 21, 2018'
    }
]

@app.route('/')
@app.route('/home')
def home():
    return render_template('home.htm', posts=posts )
@app.route('/about')
def about():
    return render_template('about.htm', title='about')

if __name__ == '__main__':
    app.run(debug=True)

Place the code below in the home.htm and about.htm

{% if title %}
    <title>Flask_Blog {{ title }}</title>
{% else %}
    <title>{{ title }}</title>
{% endif %}

If we change to url to the about page, we can see the title has changed

Part 4 - Template Comparitives

01

Create a new html or htm file and call it layout.htm, Copy and paste the html from 'about' or 'home' and delete any html that is unique to the page

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    {% if title %}
    <title>Flask_Blog {{ title }}</title>
    {% else %}
        <title>{{ title }}</title>
    {% endif %}    
</head>
<body>

</body>
</html>

We now only have the html that is shared between 'about' and 'home' in the layout.htm file

Create a block within the layout.htm file where the html unique to the page will be contained. Here we call the block content.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    {% if title %}
    <title>Flask_Blog {{ title }}</title>
    {% else %}
        <title>{{ title }}</title>
    {% endif %}    
</head>
<body>
    {% block content %}{% endblock %}
    
</body>
</html>

Within about and home, delete the html that is contained within the layout.htm file. Use the extends "layout.htm" keyword and the about and home will inherit the html from layout

{% extends 'layout.htm' %}
{% block content %}
    <h1>Home (rendered)</h1>
    {% for post in posts%}
        <h2> {{ post.title }} </h2>
        <p> By {{ post.author }} on {{ post.data_posted }} </p>
        <p> {{ post.content }} </p>
    {% endfor %}
{% endblock content %}
          

Part 5 - add bootstrap to each page

01

Visit getbootstrap.com to copy the cdn links and javascript links then paste them into your layout.htm or html file so they can be applied to each page of your site. Place the following code into the layout.htm template

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
                        
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js" integrity="sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa" crossorigin="anonymous"></script>
layout.htm
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">

    {% if title %}
    <title>Flask_Blog {{ title }}</title>
    {% else %}
        <title>{{ title }}</title>
    {% endif %}    
</head>
<body>
    <div class="container">

        {% block content %}{% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js" integrity="sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa" crossorigin="anonymous"></script>
</body>
</html>

02

The container class is a standard class from bootstrap, This might be out of date

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
{% if title %}
<title>Flask_Blog {{ title }}</title>
{% else %}
<title>{{ title }}</title>
{% endif %}
</head>

<body>
<div class="container">
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js"
integrity="sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa"
crossorigin="anonymous"></script>
</body>

</html>
                            

03

To use css file, create a static folder and place the file in there

static → css → styles.css
.container {
    margin: 0 5%;
    width: 80%;
    border: 2px solid black ;
}
                            

03b

Part 6 - add header navbar, sidebar

01

Add this header to the layout.htm file, you can find the source codes at
python/.....

    <header class="site-header">
        <nav class="navbar navbar-expand-md bg-steel ">
            <div class="container">
            <a class="navbar-brand mr-4" href="/">Flask Blog</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggle" aria-controls="navbarToggle" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarToggle">
                <div class="navbar-nav mr-auto">
                <a class="nav-item nav-link" href="/">Home</a>
                <a class="nav-item nav-link" href="/about">About</a>
                </div>
                <!-- Navbar Right Side -->
                <div class="navbar-nav">
                <a class="nav-item nav-link" href="/login">Login</a>
                <a class="nav-item nav-link" href="/register">Register</a>
                </div>
            </div>
            </div>
        </nav>
    </header>
                            

02

replace the {% block content %} with the following, you can find the source codes at
python/.....

<main role="main" class="container">
    <div class="row">
        <div class="col-md-8">
            {% block content %}{% endblock %}
        </div>
        <div class="col-md-4">
            <div class="content-section">
                <h3>Our Sidebar</h3>
                <p class='text-muted'>You can put any information here you'd like.
                <ul class="list-group">
                    <li class="list-group-item list-group-item-light">Latest Posts</li>
                    <li class="list-group-item list-group-item-light">Announcements</li>
                    <li class="list-group-item list-group-item-light">Calendars</li>
                    <li class="list-group-item list-group-item-light">etc</li>
                </ul>
                </p>
            </div>
        </div>
    </div>
</main>
                            

Part 7 - add custom css

01

To use css file, create a static folder and place the file in there

static → css → styles.css
.container {
    margin: 0 5%;
    width: 80%;
    border: 2px solid black ;
}
                        

02

This is the styles on his github, copy and paste it into your styles.css script

body {
  background: #fafafa;
  color: #333333;
  margin-top: 5rem;
}

h1, h2, h3, h4, h5, h6 {
  color: #444444;
}

.bg-steel {
  background-color: #5f788a;
}

.site-header .navbar-nav .nav-link {
  color: #cbd5db;
}

.site-header .navbar-nav .nav-link:hover {
  color: #ffffff;
}

.site-header .navbar-nav .nav-link.active {
  font-weight: 500;
}

.content-section {
  background: #ffffff;
  padding: 10px 20px;
  border: 1px solid #dddddd;
  border-radius: 3px;
  margin-bottom: 20px;
}

.article-title {
  color: #444444;
}

a.article-title:hover {
  color: #428bca;
  text-decoration: none;
}

.article-content {
  white-space: pre-line;
}

.article-img {
  height: 65px;
  width: 65px;
  margin-right: 16px;
}

.article-metadata {
  padding-bottom: 1px;
  margin-bottom: 4px;
  border-bottom: 1px solid #e3e3e3
}

.article-metadata a:hover {
  color: #333;
  text-decoration: none;
}

.article-svg {
  width: 25px;
  height: 25px;
  vertical-align: middle;
}

.account-img {
  height: 125px;
  width: 125px;
  margin-right: 20px;
  margin-bottom: 16px;
}

.account-heading {
  font-size: 2.5rem;
}
                        

Fix the margin and padding on your own accord, for now this is what it should look from the script above

This lesson is super long, I'm having an anxiety mental breakdown but i'm calm i'm writing, Place custom css in a directory called static call the file main.css

add the url_for in the flaskblog.py script

Please for the love of god last step, use the url_for function class whatever the hell it is, in a link tag in the head of the layout.htm

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
    {% if title %}
    <title>Flask_Blog {{ title }}</title>
    {% else %}
        <title>{{ title }}</title>
    {% endif %}    
</head>

Add the above code to the head in layout.htm or html and the page will look the same

Go back and add article blog html and style to {% block content %}