How to build a blogging website in Python with Flask

In this tutorial, we are going to create a blogging website with CRUD(Create, Read, Update and Delete) functionality by using the Flask web framework in Python. Before proceeding, please visit the following links.

Introduction and overview of Flask Framework and how to install it?

Official Flask Website

 

Our First Flask Webpage in Python

To continue, you must have Python and flask installed on your machine.

Now we will create our Python file to write the code,  mine is named “app.py”. We must keep this file in a separate folder.

The following line imports the Flask class from the flask package.

from flask import Flask

Now we will create an object of the Flask class which in this case is called “app”.

app = Flask(__name__)

Here __name__ is a special variable whose value depends on how we execute the script(Python file).

Next Step is to create a route decorator which binds the value of the URL provided in the route to a function.

@app.route('/home')
def Welcome():
    return "CodeSpeedy"

In the above snippet, the route decorator links the ‘/home’ URL with the Welcome function. The Welcome function, in turn, returns the string value “CodeSpeedy”.

Last Step is to make sure that we are running the script and not importing it and if we are running the script then we will run the app in Debug mode.

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

 

Note: It is not necessary to include the debug condition inside the run method of the app object But its use enables easy debugging.

Following is a screenshot of the source code:
How to build a blogging website in Python with Flask

Output:

The output will be shown on localhost:5000/home in your browser.

Here is a screenshot of the output:

localhost:5000/home flask

Note: We can also link multiple routes to the same function. The following snippet shows an example.

from flask import Flask

app = Flask(__name__)

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return "CodeSpeedy"

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

All the three URLs will show the same output which in our case is CodeSpeedy.

Using templates- flask

In the previous section, we learnt how to create our first webpage and passed text to be displayed on those web pages by returning the values from the functions inside the route decorators, we can also return HTML code from these functions but that won’t be ideal so instead, we use what is called a template.

A template is a pre-designed webpage or set of HTML webpages that anyone can use to “plug-in” their text content and images into to create a website.

We can import the render_template function from the Flask library to make use of templates on our website.

The following code snippet shows the use of templates:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return render_template('index.html')

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

To render a template, we must first create it which can be done easily by creating an HTML file.

The HTML files must be stored in a separate folder called ‘templates’.

In the above snippet we rendered the index.html which contains the following code:

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CodeSpeedy Blog</title>
</head>

<body>
    <h1>Welcome to CodeSpeedy!</h1>
</body>

</html>

Output:

The output of the above Python snippet will be:-

127.0.0.1:5000 in flask python

You can visit the following links for more information regarding templates:

Templates in Flask explained and the importance of using them

Introduction to HTML and creating your First Template(Part IX)

Creating a database model in flask

In this section, we will create a model for our database.

This database will be useful in providing CRUD functionality to our blogging website by handling the posts which will be made there.

Creating a model for our database makes easy handling of data possible.

We will use the ‘flask_sqlalchemy’ external library to handle the database operations.

The following snippet shows how to model our database:

class CodeSpeedyBlog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, unique=True)
    content = db.Column(db.Text, nullable=False)
    posted_by = db.Column(db.String(20), nullable=False, default='N/A')
    posted_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())

    def __repr__(self):
        return self.title

In the above snippet, we modeled our data but to make it work, we have to make some other adjustments and inclusions.

Here, the name of our model is CodeSpeedyBlog and it inherits from a predefined model. The attributes of the model are title, content, posted_by and posted_on. This provides us with the main information about the posts made on our blogging website.

Note: The __repr__ method returns a printable representation of the database object. In our case, this representation will be the title of the posts.

The following is the complete code for model creation:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
db = SQLAlchemy(app)


class CodeSpeedyBlog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, unique=True)
    content = db.Column(db.Text, nullable=False)
    posted_by = db.Column(db.String(20), nullable=False, default='N/A')
    posted_on = db.Column(db.DateTime, nullable=False,
                            default=datetime.utcnow())

    def __repr__(self):
        return self.title


db.create_all()
db.session.commit()

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return render_template('index.html')

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

We have configured our app to use the SQLite database with the help of flask_sqlalchemy library and we have named our database posts.db and ‘SQLite‘ was used for the database management.

We have also created a database object called ‘db’  and have used the suitable SQL syntaxes for creating and committing the database.

To know more about CRUD functionality visit:

Database CRUD Operation in Python with MySQL – Create, Retrieve, Update, Delete

Creating a new post- flask

In this section, we will define the routes and functions that are needed to create a new post on our website and will also create a template for our new post creation webpage. The name of the template is new_post.html and it must be added to the templates folder.

The following snippet shows the route decorator and the concerned functions along with the managing of database and templates accordingly.

@app.route('/posts/new', methods=['GET', 'POST'])
def new_post():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()
        return redirect('/posts')
    else:
        return render_template('new_post.html')

Note: ‘GET’ is the default method in routes but if you route to have methods like ‘POST’ then you have to add them to a list. Before using the redirect function it must be imported from flask module and the ‘posts’ route must also be created beforehand which we will be doing in the next section.

Important: A blog object will be created every time we create a new post and this object follows the CodeSpeedyBlog model.

The complete code until now is given below:

from flask import Flask, render_template, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
db = SQLAlchemy(app)


class CodeSpeedyBlog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, unique=True)
    content = db.Column(db.Text, nullable=False)
    posted_by = db.Column(db.String(20), nullable=False, default='N/A')
    posted_on = db.Column(db.DateTime, nullable=False,
                            default=datetime.utcnow())

    def __repr__(self):
        return self.title


db.create_all()
db.session.commit()

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return render_template('index.html')

@app.route('/posts/new', methods=['GET', 'POST'])
def new_post():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()
        return redirect('/posts')
    else:
        return render_template('new_post.html')

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

Remember we need to create a posts route for the above to work which we will be doing shortly.

The content of the ‘new_post.html’ template is shown below:

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>New Post</title>
</head>

<body>
    <h1>New Post:</h1>
    <hr>
    <h2>New Post:</h2>
    <form action="/posts" method="POST">
        <label for="title">Title:</label>
        <input class="form-control" type="text" name="title" id="title" placeholder="Enter Title"
            aria-label="Enter Title">
        <br>
        <label for="content">Author:</label>
        <input class="form-control" type="text" name="author" id="author" placeholder="Enter Author"
            aria-label=" Enter Author">
        <br>
        <label for="post">Post:</label>
        <textarea class="form-control" id="post" name="post" placeholder="Enter Content" aria-label=" Enter Content"
            rows="3"></textarea>
        <br>
        <input type="submit" value="Post">
    </form>
    <hr>
</body>

</html>

Creating a route for reading posts in flask

In this section, we will create a route for reading the posts along with that we will also create the ‘posts.html’ template.

This will create a section in our webpage called Posts which will contain all the posts which have been posted on our platform.

Following is the code snippet for the above purpose:

@app.route('/posts',  methods=['GET', 'POST'])
def posts():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()

        return redirect('/posts')
    else:
        all_posts = CodeSpeedyBlog.query.order_by(CodeSpeedyBlog.posted_on).all()
        return render_template('posts.html', posts=all_posts)

The render template function takes an additional parameter of posts which will be used to display the added posts.

The contents of the ‘posts.html’ template are shown below:

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>All Posts</title>
</head>

<body>
    <br>
    <div>
        <h1 style="display: inline">All Posts Here: </h1>
        <a style="display: inline" class="btn btn-success float-right" href="/posts/new">+ New Post</a>
    </div>
    <br>
    <hr>
    {% for post in posts%}
    <h2>{{post.title}}</h2>

    {% if post.author %}
    <small>Written By {{post.posted_by}} on {{post.posted_on}}</small>
    {% else%}
    <small>Written by Anonymous on {{post.posted_on}}</small>
    {% endif %}
    <p style="white-space: pre-wrap">{{post.content}}</p>
    <br>
    <a href="/posts/delete/{{post.id}}"><img
            src="https://qph.fs.quoracdn.net/main-qimg-83c6de25ed91d13a4f09fb5f11ca8853" height="50px" width="50px"></a>
    <a href="/posts/edit/{{post.id}}"><img
            src="https://www.2g-eng.com/wp-content/uploads/2016/01/design-engineering-icon-small.png" height="50px"
            width="50px"></a>
    <hr>
    {% endfor %}

</body>

</html>

Note: Some Jinja2 syntax has been used in the above template to easily handle the post data.

To know more about the Jinja web template engine visit their official site given below:

Jinja Official Website

Our ‘app.py’ file will look like this after the above changes.

from flask import Flask, render_template, redirect, request
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
db = SQLAlchemy(app)


class CodeSpeedyBlog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, unique=True)
    content = db.Column(db.Text, nullable=False)
    posted_by = db.Column(db.String(20), nullable=False, default='N/A')
    posted_on = db.Column(db.DateTime, nullable=False,
                            default=datetime.utcnow())

    def __repr__(self):
        return self.title


db.create_all()
db.session.commit()

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return render_template('index.html')

@app.route('/posts',  methods=['GET', 'POST'])
def posts():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()

        return redirect('/posts')
    else:
        all_posts = CodeSpeedyBlog.query.order_by(CodeSpeedyBlog.posted_on).all()
        return render_template('posts.html', posts=all_posts)

@app.route('/posts/new', methods=['GET', 'POST'])
def new_post():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()
        return redirect('/posts')
    else:
        return render_template('new_post.html')

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

Output: 

Running the ‘app.py’ file the localhost:5000 will look like –

build a blog website in Python with flask

If we visit localhost:5000/posts we will see-

localhost:5000/posts

The localhost:5000/posts/new will look like –

localhost:5000/posts/new

Creating an edit route

Now to add the update feature to our website, we will create the edit route so that we can update the already created posts.

The following snippet contains the edit route :

@app.route('/posts/edit/<int:id>', methods=['GET', 'POST'])
def edit(id):
    to_edit = CodeSpeedyBlog.query.get_or_404(id)
    if request.method == 'POST':
        to_edit.title = request.form['title']
        to_edit.author = request.form['author']
        to_edit.content = request.form['post']
        db.session.commit()
        return redirect('/posts')

    else:
        return render_template('edit.html', post=to_edit)

Note: We have used the ‘.get_or_404’ function to avoid crashing of our website in case the post is not found.

Now we will create the ‘edit.html’ template for our edit page which will contain the following;

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Edit Post</title>
</head>


<body>
    <h1>Editing Post: </h1>
    <hr>
    <h2>Edit:</h2>

    <form action="/posts/edit/{{post.id}}" method="POST">
        <label for="content">Title:</label>
        <input class="form-control" type="text" name="title" id="title" value="{{post.title}}">
        <br>
        <label for="content">Author:</label>
        <input class="form-control" type="text" name="author" id="author" value="{{post.posted_by}}">
        <br>
        <label for="post">Post:</label>
        <textarea class="form-control" id="post" name="post" rows="3">{{post.content}}</textarea>
        <br>
        <input type="submit" value="Save">
    </form>
    <hr>
</body>

</html>

Creating a delete route

The last feature in our CRUD app will be to delete an existing post which is done in the following code snippet:

@app.route('/posts/delete/<int:id>')
def delete(id):
    to_delete = CodeSpeedyBlog.query.get_or_404(id)
    db.session.delete(to_delete)
    db.session.commit()
    return redirect('/posts')

Note: We used the redirect function to go back to existing posts page after deleting one of them.

After following these steps our ‘app.py’ file will look like –

from flask import Flask, render_template, redirect, request
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
db = SQLAlchemy(app)


class CodeSpeedyBlog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False, unique=True)
    content = db.Column(db.Text, nullable=False)
    posted_by = db.Column(db.String(20), nullable=False, default='N/A')
    posted_on = db.Column(db.DateTime, nullable=False,
                            default=datetime.utcnow())

    def __repr__(self):
        return self.title


db.create_all()
db.session.commit()

@app.route('/')
@app.route('/home')
@app.route('/CodeSpeedy')
def Welcome():
    return render_template('index.html')

@app.route('/posts',  methods=['GET', 'POST'])
def posts():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()

        return redirect('/posts')
    else:
        all_posts = CodeSpeedyBlog.query.order_by(CodeSpeedyBlog.posted_on).all()
        return render_template('posts.html', posts=all_posts)

@app.route('/posts/delete/<int:id>')
def delete(id):
    to_delete = CodeSpeedyBlog.query.get_or_404(id)
    db.session.delete(to_delete)
    db.session.commit()
    return redirect('/posts')     

@app.route('/posts/edit/<int:id>', methods=['GET', 'POST'])
def edit(id):
    to_edit = CodeSpeedyBlog.query.get_or_404(id)
    if request.method == 'POST':
        to_edit.title = request.form['title']
        to_edit.author = request.form['author']
        to_edit.content = request.form['post']
        db.session.commit()
        return redirect('/posts')

    else:
        return render_template('edit.html', post=to_edit)

@app.route('/posts/new', methods=['GET', 'POST'])
def new_post():
    if request.method == 'POST':
        post_title = request.form['title']
        post_content = request.form['post']
        post_author = request.form['author']
        new_post = CodeSpeedyBlog(title=post_title,
                        content=post_content, posted_by=post_author)
        db.session.add(new_post)
        db.session.commit()
        return redirect('/posts')
    else:
        return render_template('new_post.html')

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

This is our final ‘app.py’ file

Using Jinja2  in Templates

Earlier when we made our templates who must have noticed all of them had some common elements in them But still we had to write them again and again for all the templates, Jinja2 enables us to write the repetitive part of our templates only once and than use it in other templates.

In order to take leverage of this functionality of the Jinja 2 engine, we must create a base template from which other templates will inherit.

The base template will contain common elements.

The base template just like any template can be created by making an HTML file in our case it’s named “base.html”.

Following is the code for our “base.html” file:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="description" content = "Your day to day blogging website.">
    <meta name="author" content="You">	    
{% block head %} {% endblock%}
</head>
<body>
    <div class="container">
    {% block body %} {% endblock%}      
</body>
</html>

We have used the following in our template

{% block head %} {% endblock%}

The above syntax will be replaced by the content present in similar blocks of different templates that inherit from our base template which we will see shortly.

This block has been made for the head area.

 {% block body %} {% endblock%}

Similarly, the above syntax is created for body area and it will be replaced by the content present in a similar block of different templates that inherit from our base template.

Our modified “index.html” file will look like:

{% extends 'base.html' %}
{% block head %}
<title>Home Page </title>
{% endblock%}

{% block body %}
<br>
<h1>Home Page</h1>
<br>
{% endblock%}

The first line depicts that this file inherits from our base template.

The index file’s head blog contains its title while the body blog has the heading “Home Page”.

Our modified “posts.html” will look like this:

{% extends 'base.html' %}
{% block head %}
<title>Posts Page </title>
{% endblock%}

{% block body %}
<br>
    <div>
        <h1 style="display: inline">All Posts Here: </h1>
        <a style="display: inline" class="btn btn-success float-right" href="/posts/new">+ New Post</a>
    </div>
    <br>
    <hr>
    {% for post in posts%}
    <h2>{{post.title}}</h2>

    {% if post.author %}
    <small>Written By {{post.posted_by}} on {{post.posted_on}}</small>
    {% else%}
    <small>Written by Anonymous on {{post.posted_on}}</small>
    {% endif %}
    <p style="white-space: pre-wrap">{{post.content}}</p>
    <br>
    <a href="/posts/delete/{{post.id}}"><img
            src="https://qph.fs.quoracdn.net/main-qimg-83c6de25ed91d13a4f09fb5f11ca8853" height="50px" width="50px"></a>
    <a href="/posts/edit/{{post.id}}"><img
            src="https://www.2g-eng.com/wp-content/uploads/2016/01/design-engineering-icon-small.png" height="50px"
            width="50px"></a>
    <hr>
    {% endfor %}

{% endblock%}

It also follows the same structure.

Next will be our “edit.html” file:

{% extends 'base.html' %}
{% block head %}
<title>Edit Page</title>
{% endblock%}

{% block body %}
<h1>Editing Post: </h1>
<hr>
<h2>Edit:</h2>

<form action="/posts/edit/{{post.id}}" method="POST">
    <label for="content">Title:</label>
    <input class="form-control" type="text" name="title" id="title" value="{{post.title}}">
    <br>
    <label for="content">Author:</label>
    <input class="form-control" type="text" name="author" id="author" value="{{post.author}}">
    <br>
    <label for="post">Post:</label>
    <textarea class="form-control" id="post" name="post" rows="3">{{post.content}}</textarea>
    <br>
    <input type="submit" value="Save">
</form>
<hr>
{% endblock%}

The “new_post.html” file will look like this:

{% extends 'base.html' %}
{% block head %}
<title>New Post</title>
{% endblock%}

{% block body %}
<h1>New Post:</h1>
<hr>
<h2>New Post:</h2>
<form action="/posts" method="POST">
    <label for="title">Title:</label>
    <input class="form-control" type="text" name="title" id="title" placeholder="Enter Title" aria-label="Enter Title">
    <br>
    <label for="content">Author:</label>
    <input class="form-control" type="text" name="author" id="author" placeholder="Enter Author"
        aria-label=" Enter Author">
    <br>
    <label for="post">Post:</label>
    <textarea class="form-control" id="post" name="post" placeholder="Enter Content" aria-label=" Enter Content"
        rows="3"></textarea>
    <br>
    <input type="submit" value="Post">
</form>
<hr>
{% endblock%}

All our templates have been updated now with the help of Jinja2.

Using Bootstrap

Our website is almost complete now although we can add some features to enhance the look of our website one of such features is called Bootstrap. Bootstrap is a free and open-source CSS framework used for developing responsive websites

You can learn more about Bootstrap from their official website given below:

Bootstrap Official Website

Before we can add Bootstrap features in our templates we have to add a link to the Bootstrap files with the help of the following link tag:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

We must add this link tag at the top of the head tag in our base template.

We must also add the following javascript code just before the end of the body tag in our base template.

<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
            integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
            crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"
            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
            crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
            integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
            crossorigin="anonymous"></script>

Both the above link and script tags can be found at the official Bootstrap website.

Now we can add some predefined bootstrap examples on our website. The most useful is the navigation bar whose snippet is :

<nav class="navbar navbar-dark bg-dark">
        <a class="navbar-brand" href="/">CodeSpeedy Blog</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample01"
            aria-controls="navbarsExample01" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarsExample01">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/posts">Posts</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown"
                        aria-haspopup="true" aria-expanded="false">Contact Us</a>
                    <div class="dropdown-menu" aria-labelledby="dropdown01">
                        <a class="dropdown-item" href="#">Instagram</a>
                        <a class="dropdown-item" href="#">Gmail </a>
                        <a class="dropdown-item" href="#">Website</a>
                    </div>
                </li>
            </ul>
            <form class="form-inline my-2 my-md-0">
                <input class="form-control" type="text" placeholder="Search" aria-label="Search">
            </form>
        </div>
    </nav>

The above snippet must be added inside the body tag of our base.html file.

Our final base.html file will look like this:

<html lang="en">
<head> 
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
<meta http-equiv="X-UA-Compatible" content="ie=edge"> 
<meta name="description" content = "Your day to day blogging website."> 
<meta name="author" content="You"> 
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> 
{% block head %}
{% endblock%}
</head> 
<body>
<nav class="navbar navbar-dark bg-dark"> 
<a class="navbar-brand" href="/">CodeSpeedy Blog</a> 
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample01" aria-controls="navbarsExample01" aria-expanded="false" aria-label="Toggle navigation"> 
<span class="navbar-toggler-icon">
</span> 
</button> 
<div class="collapse navbar-collapse" id="navbarsExample01"> 
<ul class="navbar-nav mr-auto"> 
<li class="nav-item active"> 
<a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a> 
</li> 
<li class="nav-item"> 
<a class="nav-link" href="/posts">Posts</a> 
</li> 
<li class="nav-item dropdown"> 
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Contact Us</a> 
<div class="dropdown-menu" aria-labelledby="dropdown01"> 
<a class="dropdown-item" href="#">Instagram</a> 
<a class="dropdown-item" href="#">Gmail </a> 
<a class="dropdown-item" href="#">Website</a> 
</div> 
</li> 
</ul> 
<form class="form-inline my-2 my-md-0"> 
<input class="form-control" type="text" placeholder="Search" aria-label="Search"> 
</form> 
</div> 
</nav>
<div class="container"> 
{% block body %} 
{% endblock%}
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> 
</body> 
</html>

Our website will look like this after the above changes:

build a blogging website with flask

Now we have given our website some decent features the look of our website can be improved further as per our need.

Deploying our website

We can deploy our flask website on any hosting platform, one of the easiest ways is through “PythonAnywhere.com”. Following is a link on how to host our web application on PythonAnywhere.com.

How to host your Web Application on PythonAnywhere.com

 

Congratulations your website is live!

Hope this tutorial helped you to understand how you can create a blogging website in Flask.

Feel free to drop any queries you face in the whole procedure.

 

After completing this tutorial you can check the following Django tutorial to learn more about web development in Python:

How to create a blog website in Django – Beginner tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *