Converting a Static HTML Website to a Dynamic Website using Python and Flask
Learn how to convert your static HTML website into a professional dynamic website using the Flask framework in Python, with step-by-step practical examples tailored for freelancers.
Word count: ~1800 · Reading time: 9 minutes
Building Dynamic Websites with Python
How to transform your static web project into a dynamic site using Python and Flask
Note to the reader: This article is completely standalone; you can implement everything here without reading previous posts. However, if you haven’t installed Python or set up your work environment yet, we recommend checking our article: Installing Python and Setting Up a Professional Environment.
Assume you have designed a website using HTML and CSS, and perhaps added some JavaScript effects. The result is clean, tidy, and professional, but it is dead. Every page is a static file, and every change requires manual code editing. It cannot receive data from users, generate pages automatically, or communicate with a database. This is the wall most designers and freelancers hit after mastering HTML.
The solution is Backend development. Python offers this through a lightweight, professional framework called Flask. In this article from Zy Yazan Platform, we will build your first real dynamic website on your local machine. It will handle requests, generate intelligent HTML pages, and respond to forms—all with just a few lines of Python.
What is the real difference between a static and a dynamic site?
Before writing a single line of code, let’s understand the basic equation. When you visit a static site, the server reads an HTML file from the disk and sends it to you; it’s done, no thinking or processing involved. When you visit a dynamic site, the server receives your request, understands it, decides what to send, builds the page on the fly, and then sends it to you.
A static site is like a printed book that never changes, while a dynamic site is like a conversation—it listens to you and responds based on what you said.
This means a dynamic site can:
- Display a user’s name after login
- Generate a unique page for each product or article without writing them manually
- Receive contact forms and send emails
- Read data from a database and display it to visitors
- Change content based on time, location, or user behavior
What is Flask, and why choose it?
Flask is a web framework written in Python, released in 2010. It remains one of the most popular frameworks in the world. Its core philosophy is simple: provide the bare minimum needed to build a website, and let you add what you need.
Why choose “Flask” over “Django,” for instance? This is a valid question we will address in detail in the tenth article of this series. But the short answer for now: Flask is faster to learn and less complex for small to medium projects, making it the ideal starting point for backend development.
| Feature | Static Site (HTML only) | Flask (Python + HTML) |
|---|---|---|
| Multiple pages | Manual HTML file for each | One template generates thousands |
| User input | Impossible without 3rd party | Direct and fully controlled |
| Database connection | No | Yes, full support |
| Learning curve | Very easy | Moderate — learn in hours |
| Freelance Market Value | Frontend designer only | Junior Full-Stack developer |
Step 1: Installing Flask
Open your Terminal, ensure your virtual environment is activated, and type:
pip install flask
Wait a few seconds for the process to complete. To verify the installation:
python -c "import flask; print(flask.__version__)"
If the Flask version appears, you are ready.
Your first Flask app: Under 10 lines
Create a folder named my_flask_app, create a file named app.py inside it, and add the following:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "<h1>Welcome to your first dynamic website!</h1>"
@app.route("/about")
def about():
return "<p>This is Flask — Python serving the web.</p>"
if __name__ == "__main__":
app.run(debug=True)
Run the file:
python app.py
A message will tell you the server is running on http://127.0.0.1:5000. Open your browser to this address, and you will find your site live! Also try http://127.0.0.1:5000/about.
Understanding what just happened: @app.route("/") tells Flask that when a request reaches the homepage, it executes the home() function and returns what it produces. This is the core of Backend programming: mapping a URL to code that handles it.
The real step: Using HTML templates instead of coding HTML inside Python
Writing HTML directly inside Python is not a good idea for any real project. Flask solves this with a feature called Jinja2 Templating, which allows you to write standard HTML and inject Python data dynamically.
Create the following project structure:
my_flask_app/
│
├── app.py
├── templates/
│ ├── base.html
│ ├── index.html
│ └── portfolio.html
└── static/
├── style.css
└── logo.png
The templates folder is where Flask looks for HTML files. The static folder is for static files like CSS and images.
Creating the Base Template (base.html)
The base template is Jinja’s most powerful concept. Design your site structure once (Header, Navbar, Footer) and inherit it in all other pages:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page_title }} | My Professional Site</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/portfolio">Portfolio</a>
<a href="/contact">Contact</a>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>All rights reserved {{ current_year }}</p>
</footer>
</body>
</html>
Note the double brackets {{ }} — this is Jinja2 syntax to inject Python variables. {% block content %} is where each page will place its unique content.
Home Page (index.html)
{% extends "base.html" %}
{% block content %}
<section class="hero">
<h1>Hello, I am {{ freelancer_name }}</h1>
<p>Web Developer specializing in {{ specialty }}</p>
<a href="/portfolio" class="btn">View my work</a>
</section>
<section class="stats">
<div><strong>{{ projects_count }}</strong> projects completed</div>
<div><strong>{{ clients_count }}</strong> satisfied clients</div>
<div><strong>{{ years_exp }}</strong> years experience</div>
</section>
{% endblock %}
Updating app.py to pass data to templates
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
# Your data — change as you wish
FREELANCER_DATA = {
"name": "Alex the Freelancer",
"specialty": "Web development & Python automation",
"projects_count": 47,
"clients_count": 23,
"years_exp": 4
}
@app.route("/")
def home():
return render_template(
"index.html",
page_title="Home",
freelancer_name=FREELANCER_DATA["name"],
specialty=FREELANCER_DATA["specialty"],
projects_count=FREELANCER_DATA["projects_count"],
clients_count=FREELANCER_DATA["clients_count"],
years_exp=FREELANCER_DATA["years_exp"],
current_year=datetime.now().year
)
if __name__ == "__main__":
app.run(debug=True)
The render_template() function takes the HTML filename and any number of variables you want to pass. Flask automatically finds the file in the templates folder, merges the data into the template, and sends the rendered page to the browser.
Comprehensive example: A dynamic Portfolio page
This is the example that will impress you. Instead of creating a separate HTML page for each project, we will store projects in a Python list and let it generate the pages automatically.
Add this code to app.py:
# Your projects list — in real apps, this comes from a database
PROJECTS = [
{
"id": 1,
"title": "E-commerce store",
"category": "Web Development",
"description": "WooCommerce store with local payment gateway.",
"tech": ["WordPress", "PHP", "Python"],
"url": "#"
},
{
"id": 2,
"title": "Email Automation Tool",
"category": "Automation",
"description": "Python script to send 500 personalized emails.",
"tech": ["Python", "smtplib", "pandas"],
"url": "#"
}
]
@app.route("/portfolio")
def portfolio():
return render_template("portfolio.html", page_title="Portfolio", projects=PROJECTS)
@app.route("/portfolio/<int:project_id>")
def project_detail(project_id):
project = next((p for p in PROJECTS if p["id"] == project_id), None)
if project is None:
return "<h1>Project not found</h1>", 404
return render_template("project_detail.html", page_title=project["title"], project=project)
And now for portfolio.html:
{% extends "base.html" %}
{% block content %}
<h1>My Portfolio</h1>
<div class="projects-grid">
{% for project in projects %}
<div class="project-card">
<span class="category">{{ project.category }}</span>
<h2>{{ project.title }}</h2>
<p>{{ project.description }}</p>
<div class="tech-tags">
{% for tech in project.tech %}
<span class="tag">{{ tech }}</span>
{% endfor %}
</div>
<a href="/portfolio/{{ project.id }}">View Details</a>
</div>
{% endfor %}
</div>
{% endblock %}
{% for project in projects %} is a Jinja2 loop—just like a Python loop, but it runs inside HTML. Flask repeats the div.project-card block for each project automatically. Add a new project to your Python list, and it appears on the page immediately without touching HTML.
Handling HTML Forms: Contact page
Half the value of any dynamic site lies in receiving data from visitors. Let’s build a contact form to receive messages.
Add this code to app.py:
from flask import request
@app.route("/contact", methods=["GET", "POST"])
def contact():
message_sent = False
if request.method == "POST":
# Process form data
name = request.form.get("name", "").strip()
# Save to file or database logic here...
message_sent = True
return render_template("contact.html", page_title="Contact", message_sent=message_sent)
The function handles two types of requests: GET to show the form, and POST to process sent data. request.form.get() extracts the value of each field.
Connecting to static files (CSS/JS)
If you already have a beautiful HTML site, just move your CSS/JS and image files to the static folder, then update your links in the templates using:
<!-- Instead of -->
<link rel="stylesheet" href="style.css">
<!-- Use -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
url_for() automatically converts the filename into its full URL, ensuring your code works in any hosting environment.
Publishing your site online
Your site currently runs on your device only (Localhost). For real hosting, common options for freelancers include:
- PythonAnywhere: Free for small sites, supports Flask directly.
- Render: Generous free tier, deploy with one click from GitHub.
- Railway: Simple and suitable for small projects.
- VPS (Hostinger / DigitalOcean): For professional projects requiring full control.
Practical advice: Start with PythonAnywhere or Render for any pilot project. Once your site grows and generates revenue, upgrade to a VPS to save bandwidth costs and gain higher performance.
What services can you sell as a freelancer now?
Once you master Flask, you open up new services with much higher value than static design:
- Dynamic portfolio sites for clients: Editable via a simple dashboard.
- Booking/Scheduling systems: Receives booking requests and sends automatic confirmations.
- Smart landing pages: Collects leads and sends them to Google Sheets.
- Simple API interfaces: Sell your data or tools to other developers.
- Internal reporting dashboards: Visualizing data for companies.
Summary and next steps
Today we passed the biggest barrier for web designers: moving from static pages to true Backend development. We learned how Flask handles requests, how Jinja2 templates work, how to build an expandable portfolio, and how to process forms.
Recommended next step:
You’ve mastered the basics of Flask—now for the strategic question: do you stick with Flask for large projects, or switch to the Django framework for more extensive capabilities? Both are Python, but their philosophies differ radically. In the next article, we provide the ultimate comparison.
Follow the tenth article: Django vs Flask? Which one to choose as a freelancer in 2026.
References:
- Flask Official Documentation: Flask Official Documentation
- Jinja2 Template Guide: Jinja2 Template Designer Documentation
- MDN Guide to HTTP: MDN Web Docs — HTTP request methods

