Looking to showcase your projects, skills, and personal brand online? A Python Flask portfolio website offers a lightweight, customizable, and SEO‑friendly solution that can grow with you. In this guide we’ll walk through every step of building a polished portfolio from scratch—setting up the environment, crafting clean routes, styling with Jinja2 templates, adding a functional contact form, and deploying the final product. Whether you’re a recent graduate, a freelance developer, or simply a tech enthusiast, this Flask portfolio project will give you a professional web presence while sharpening your Python web‑development chops.
Why Flask Is the Ideal Choice for a Portfolio Site
Flask is a micro‑framework that provides just enough structure to get a web app running without the overhead of larger frameworks like Django. Here are the key reasons it shines for a personal portfolio:
- Flexibility: You decide the folder layout, templating engine, and extensions, so the site can stay as simple or as complex as you need.
- Fast Development Cycle: With built‑in development server and auto‑reloader, changes appear instantly, letting you iterate quickly.
- SEO‑Friendly: Flask renders HTML on the server, making it easy for search engines to crawl and index your content.
- Lightweight Hosting: Most PaaS providers (Heroku, Render, Fly.io) support Flask out of the box, keeping deployment costs low.
- Python Ecosystem: Leverage powerful libraries—SQLAlchemy for data, WTForms for forms, and Flask‑Mail for email handling—without learning a new language.
Project Overview: What the Portfolio Will Include
Our final portfolio will contain the following core pages and features:
- Home: A hero section with a brief intro, animated background, and call‑to‑action buttons.
- About: A narrative about your background, skills, and professional journey.
- Projects: A dynamic grid that pulls project data from a JSON file or simple SQLite database.
- Blog (optional): A lightweight blog powered by Markdown files for SEO‑rich content.
- Contact: A secure contact form that sends messages to your email via Flask‑Mail.
All pages will share a common base template, use Bootstrap 5 for responsive design, and include meta tags optimized for search engines.
Setting Up the Development Environment
Before writing any code, ensure your workstation is ready for Flask development.
# 1. Install Python (>=3.9) and create a virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
# 2. Install Flask and essential extensions
pip install Flask Flask-WTF Flask-Mail Flask-Login
# 3. Verify installation
python -c "import flask; print(flask.__version__)"
Keeping dependencies isolated in a venv prevents version conflicts and makes deployment smoother.
Building the Core Routes with Flask
Flask routes map URLs to Python functions. Below is a minimal app.py that defines the main pages of our portfolio.
from flask import Flask, render_template, request, flash, redirect, url_for
from flask_mail import Mail, Message
app = Flask(__name__)
app.config['SECRET_KEY'] = 'replace-with-a-secure-key'
# Mail configuration (example using Gmail)
app.config.update(
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=587,
MAIL_USE_TLS=True,
MAIL_USERNAME='your.email@gmail.com',
MAIL_PASSWORD='your-app-password'
)
mail = Mail(app)
@app.route('/')
def home():
return render_template('home.html', title='Home')
@app.route('/about')
def about():
return render_template('about.html', title='About Me')
@app.route('/projects')
def projects():
# In a real app, load projects from a database or JSON file
project_list = [
{'name': 'Flask Blog', 'description': 'A simple blog built with Flask.'},
{'name': 'Data Dashboard', 'description': 'Interactive charts using Plotly.'}
]
return render_template('projects.html', title='My Projects', projects=project_list)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
message_body = request.form['message']
msg = Message(subject=f'Portfolio Contact from {name}',
sender=app.config['MAIL_USERNAME'],
recipients=['your.email@gmail.com'],
body=f'From: {name} <{email}>\n\n{message_body}')
mail.send(msg)
flash('Your message has been sent successfully!', 'success')
return redirect(url_for('contact'))
return render_template('contact.html', title='Contact Me')
if __name__ == '__main__':
app.run(debug=True)
Notice the use of render_template to keep HTML separate from Python logic—this is a best practice for maintainability and SEO.
Designing the Layout with Jinja2 Templates
Flask uses Jinja2 as its templating engine. Create a templates/ folder with a base layout that all pages extend.
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} | My Flask Portfolio</title>
<meta name="description" content="Showcasing my projects and skills built with Python Flask.">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('home') }}">My Portfolio</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="{{ url_for('home') }}">Home</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('about') }}">About</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('projects') }}">Projects</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('contact') }}">Contact</a></li>
</ul>
Leave a Reply