Python Flask Portfolio Website Project

Written by

in

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‑SQLAlchemy or Flask‑Mail when 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:

  1. A home page that introduces you and highlights key skills.
  2. A projects page that pulls data from a JSON file (or a database) and displays each project with images, descriptions, and links.
  3. 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 %}

© {{ current_year }} Your Name. All rights reserved.

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 %} {% 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.

Comments

Leave a Reply

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