Photo by Chris Ried on Unsplash
How to build a Blog using Flask
How to use Flask (Python), HTML and CSS to create our very first blog
Flask is a micro web framework written in Python that speeds up application development by providing essential back-end components for programmers to build upon. Flask is simple and lightweight—one of the most manageable frameworks around—and contains only the vital necessities for web development. It is, however, also designed to be highly extensible so developers can customize it however they see fit.
Set Ups
In this tutorial we have to be familiar with Python, HTML and CSS.
we have to setup the following before starting
Steps
Step 1 - Create your Project Folder
$ mkdir samdamiblog
$ cd samdamiblog
Step2 - Virtual Environment
Create a virtual environment.
NOTE: We have different way of creating a virtual environment depending on your Operating System (OS) but in this tutorial we are using Windows OS
Name your virtual environment venv
$ py -3 -m venv venv
Activate the environment
NOTE: Before you work on your project, activate the corresponding environment:
$ venv\Scripts\activate
Install Flask
After you activated your environment, we use the following command to install Flask:
$ pip install Flask
NOTE: In Python, pip is a standard package management system that is used to install and manage other software modules.
Now Flask is installed.
now we open our VS Code:
$ code.
Step3 - app.py
create a folder named app.py then input this code
from flask import Flask
app = Flask(__name__)
Step4 - Database
The database is a collection of organized information that can easily be used, managed, update. Learn more …
Now we will install Flask-SQLAlchemy:
$ pip install Flask-SQLAlchemy
we import:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
Configuration:
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + os.path.join(base_dir, 'my_login.db')
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = '5e0b18fd5de07e49f80cb4f8'
We will create a database object using the SQLAlchemy
class
db = SQLAlchemy(app)
Now we create two database model.
Firstly, we install Flask-login and install UserMixin.
NOTE: We can run our code on VS Code terminal.
$ pip install Flask-Login
from flask_login import UserMixin
Then we create our user class and BlogPost class:
class User(db.Model, UserMixin):
"""This is the User database model"""
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(255), nullable=False, unique=True)
email = db.Column(db.String(255), nullable=False, unique=True)
password_hash = db.Column(db.Text(), nullable=False)
def __repr__(self):
return f"User <{self.username}>"
class BlogPost(db.Model):
"""This is the blogpost database model"""
id = db.Column(db.Integer(), primary_key=True)
title = db.Column(db.String(50))
subtitle = db.Column(db.String(50))
date_posted = db.Column(db.DateTime)
content = db.Column(db.Text)
author = db.Column(db.Text)
@app.before_first_request
def create_tables():
db.create_all()
Step5 - Routes
Routing is the mechanism of mapping the URL directly to the code that creates the webpage. Learn more here...
We import the code:
from flask import Flask, render_template, url_for, request, redirect
Now create a home route.
NOTE: The home page is also the index page and represented in this format ('/') in routing.
@app.route('/')
def index():
return render_template('index.html', posts=BlogPost.query.all())
create an about route:
@app.route('/about')
def about):
return render_template('about.html')
create a contact route:
@app.route('/contact')
def contact():
return render_template('contact.html')
NOTE: The return render_template('.html') is use to connect the HTML to the route, it a function that collects data from the linked HTML file.
Step6 - Link HTML and CSS to Flask
Now we link our HTML and CSS the Flask by creating a folder called templates under our blog folder
NOTE: All the HTML file created would be under the templates folder
Then create another folder named static the folder would contain our linked image files and CSS
You can check out my codes here...
Learn more on how to link HTML and CSS to Flask here...
Step7 - Security/Route
First, we instance LoginManager(): to use Flask-Login:
login_manager = LoginManager(app)
Now input these codes:
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required, LoginManager, UserMixin, current_user
Then our code would look like this:
from flask import Flask, render_template, url_for, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required, LoginManager, UserMixin, current_user
import os
Werkzeug.security module documentation Undocumented def check_password_hash (pwhash, password): Check a password against a given salted and hashed password value. Learn more here...
Now we create our Login and Logout Route:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('index'))
else:
return render_template('login.html', error_msg="Invalid username or password. Try again.")
return render_template('login.html')
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/protected')
@login_required
def protected():
return render_template('protected.html')
Then create a Sign-up Route the allows users who doesn't have an account to create one:
@app.route('/signup', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
email = request.form.get('email')
password = request.form.get('password')
confirm = request.form.get('confirm')
passwords_no_match = ""
if confirm != password:
passwords_no_match = "The two passwords must match"
username_exists = User.query.filter_by(username=username).first()
email_exists = User.query.filter_by(email=email).first()
if username_exists or email_exists or passwords_no_match:
username_msg = "This Username is already being used by another user."
email_msg = "This Email is already being used by another user."
return render_template('signup.html', username_error=username_msg, email_error=email_msg, password_error=passwords_no_match)
password_hash = generate_password_hash(password)
new_user = User(username=username, email=email, password_hash=password_hash)
db.session.add(new_user)
db.session.commit()
return redirect(url_for('login'))
return render_template('signup.html')
We will create the Add, Edit and Delete post route also linked to their HTML file. Also adding a security in which unregister user can only read post and only allow the owner of the post to edit and delete his/her post.
@app.route('/add')
def add():
if current_user.is_authenticated:
return render_template('add.html')
else:
return redirect(url_for('login'))
@app.route('/post_deleted')
def post_deleted():
"""Notifies a user whether the delete operation was successful or not"""
return render_template('post_deleted.html')
@app.route('/posts/<int:post_id>/delete')
def delete(post_id):
post_to_be_del = BlogPost.query.filter_by(id=post_id).one()
if current_user.is_authenticated and current_user.username == post_to_be_del.author:
BlogPost.query.filter_by(id=post_id).delete()
db.session.commit()
return redirect(url_for('post_deleted'))
else:
return redirect(url_for('login'))
@app.route('/posts/<int:post_id>/edit', methods=['GET', 'POST'])
def edit_post(post_id):
post_to_be_edited = BlogPost.query.filter_by(id=post_id).one()
if current_user.is_authenticated and current_user.username == post_to_be_edited.author:
if request.method == 'GET':
return render_template('edit_post.html', post=post_to_be_edited)
elif request.method == 'POST':
post_to_be_edited.title = request.form['title']
post_to_be_edited.subtitle = request.form['subtitle']
post_to_be_edited.content = request.form['content']
db.session.commit()
return redirect(url_for('post', post_id=post_id))
else:
return redirect(url_for('login'))
@app.route('/addpost', methods=['POST'])
def addpost():
title = request.form['title']
subtitle = request.form['subtitle']
content = request.form['content']
author = current_user.username
post = BlogPost(title=title, subtitle=subtitle, content=content, author=author, date_posted=datetime.now())
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
Then you run your code using:
python app.py
and your terminal should look like this:
Step8- Requirements.txt
Requirements.txt file this allow anyone who want to access your code know the required package to install for the codes to run.
First create a folder named Requirements.txt under your blog folder the input the required package to install:
autopep8==1.7.0
click==8.1.3
Flask==2.2.2
Flask-Login==0.6.2
Flask-SQLAlchemy==2.5.1
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
pycodestyle==2.9.1
SQLAlchemy==1.4.41
toml==0.10.2
Werkzeug==2.2.2
How to install this Requirements.txt:
pip freeze > requirements.txt
pip install -r requirements.txt
Conclusion
Thanks for going through the tutorial
I hope we learnt how to create our very first blog using Flask (python) and some basics HTML and CSS knowledge.
Thanks to AltSchool Africa for this opportunity.
You can check out more of my project here..