Building a Python Flask portfolio website is a fantastic way to showcase your projects, demonstrate your web development skills, and create a personal brand that stands out to recruiters and clients. In this step‑by‑step guide you’ll learn how to set up a clean, responsive portfolio using Flask, organize your code for scalability, and optimize the site for search engines—all while keeping the project beginner‑friendly and highly customizable.
Why Choose Flask for a Portfolio Site?
Flask is a lightweight micro‑framework that gives you full control over the structure of your application. Unlike heavyweight CMS platforms, Flask lets you:
- Write clean Python code without the overhead of a full‑stack framework.
- Integrate Jinja2 templates for dynamic HTML rendering.
- Easily add extensions such as
Flask‑SQLAlchemyorFlask‑Mailwhen you need more features. - Deploy to any platform that supports WSGI, from Heroku to Render or your own VPS.
Project Overview
Our portfolio will consist of three main parts:
- A home page that introduces you and highlights key skills.
- A projects page that pulls data from a JSON file (or a database) and displays each project with images, descriptions, and links.
- A contact form that sends messages directly to your email using
Flask‑Mail.
All pages will be responsive, SEO‑friendly, and easy to extend.
Step 1: Setting Up the Development Environment
First, make sure you have Python 3.9+ installed. Then create a virtual environment and install Flask.
python -m venv venv
source venv/bin/activate # On Windows use: venv\Scripts\activate
pip install Flask Flask-Mail
Optional extensions for future growth:
pip install Flask-SQLAlchemy Flask-WTF python-dotenv
Step 2: Project Folder Structure
A well‑organized directory makes maintenance painless. Below is a recommended layout:
portfolio/
│
├─ app/
│ ├─ __init__.py # Application factory
│ ├─ routes.py # View functions
│ ├─ models.py # (optional) Database models
│ ├─ static/
│ │ ├─ css/
│ │ │ └─ style.css
│ │ ├─ img/
│ │ │ └─ profile.jpg
│ │ └─ js/
│ │ └─ main.js
│ └─ templates/
│ ├─ base.html
│ ├─ index.html
│ ├─ projects.html
│ └─ contact.html
│
├─ data/
│ └─ projects.json # Project metadata
│
├─ .env # Environment variables
├─ config.py # Configuration settings
└─ run.py # Entry point
Step 3: Creating the Flask Application Factory
Using an application factory keeps the code testable and allows multiple instances (e.g., for testing).
# app/__init__.py
from flask import Flask
from flask_mail import Mail
from config import Config
mail = Mail()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
mail.init_app(app)
from . import routes
app.register_blueprint(routes.main_bp)
return app
Step 4: Defining Routes and Views
All page logic lives in routes.py. We’ll use a Blueprint for clean separation.
# app/routes.py
from flask import Blueprint, render_template, request, flash, redirect, url_for, current_app
from flask_mail import Message
import json, os
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def home():
return render_template('index.html')
@main_bp.route('/projects')
def projects():
# Load project data from JSON
data_path = os.path.join(current_app.root_path, '..', 'data', 'projects.json')
with open(data_path) as f:
projects = json.load(f)
return render_template('projects.html', projects=projects)
@main_bp.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
message = request.form['message']
msg = Message(subject=f'Portfolio Contact from {name}',
sender=current_app.config['MAIL_DEFAULT_SENDER'],
recipients=[current_app.config['MAIL_USERNAME']],
body=f'Name: {name}\\nEmail: {email}\\n\\n{message}')
mail.send(msg)
flash('Your message has been sent!', 'success')
return redirect(url_for('main.contact'))
return render_template('contact.html')
Step 5: Building SEO‑Friendly Templates
Each template inherits from base.html, which contains meta tags, Open Graph data, and a clean navigation bar.
{% block title %}My Flask Portfolio{% endblock %}
{% block content %}{% endblock %}
Home Page (index.html)
{% extends "base.html" %}
{% block title %}Home | My Flask Portfolio{% endblock %}
{% block content %}
Hello, I’m Your Name
Full‑stack developer specializing in Python, Flask, and modern JavaScript frameworks.
View My Work
{% endblock %}
Projects Page (projects.html)
{% extends "base.html" %}
{% block title %}Projects | My Flask Portfolio{% endblock %}
{% block content %}
Featured Projects
{% for project in projects %}
{{ project.title }}
{{ project.description }}
Live Demo
Source Code
{% endfor %}
{% endblock %}
Contact Page (contact.html)
{% extends "base.html" %}
{% block title %}Contact | My Flask Portfolio{% endblock %}
{% block content %}
Get In Touch
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
{% endblock %}
Step 6: Managing Project Data with JSON
Storing project details in a JSON file keeps the site static‑friendly and avoids a full database for a simple portfolio.
# data/projects.json
[
{
"title": "Flask Blog",
"description": "A multi‑user blog built with Flask, SQLAlchemy, and Bootstrap.",
"image": "flask_blog.png",
"link": "https://example.com/flask-blog",
"repo": "https://github.com/username/flask-blog"
},
{
"title": "REST API Service",
"description": "A JSON‑based REST API for managing tasks, secured with JWT.",
"image": "rest_api.png",
"link": "https://example.com/rest-api",
"repo": "https://github.com/username/rest-api"
}
]
Step 7: Configuring Environment Variables and Mail Settings
Never hard‑code credentials. Use a .env file and load it with python-dotenv.
Leave a Reply