Python is an extremely versatile programming language that can be used for everything from data science and machine learning to building web applications. Thanks to web frameworks like Django and Flask, it‘s easy to get started with Python web development even if you don‘t have much prior experience.

In this comprehensive guide, we‘ll walk through how to build and deploy a basic website using Python and the Flask framework.

Why Use Python and Flask for Web Development

There are many reasons why Python and Flask are great choices for web development:

  • Python is beginner-friendly. The syntax is clear and intuitive, making it easy to learn even if you‘re new to programming.

  • Flask has a small footprint. Unlike monolithic frameworks like Django, Flask contains only the bare essentials needed for web development, making it fast and lightweight.

  • Setting up a Flask app is quick. You can have a simple Flask app up and running in just a few minutes.

  • There are extensive libraries and tools available. Python and Flask have rich ecosystems of third-party libraries, extensions, and tools to speed up development.

  • Flask is flexible and scalable. Small Flask apps are easy to containerize and deploy to scale. Many large websites and web apps run on Flask.

For small personal projects or MVPs, Flask provides all the power and flexibility you need without unnecessary complexity. Let‘s see how this works in practice by building a website from scratch.

Install Prerequisites

Before we begin coding, make sure Python 3 and pip (the Python package installer) are installed on your system.

Create and activate a virtual environment to isolate the project dependencies from your system‘s Python environment.

Install Flask and any other libraries you plan to use:

pip install flask gunicorn

That‘s it for setup! We are now ready to start building.

Minimal Flask Application

Let‘s start by creating the most basic Flask app that displays "Hello World!".

Create an app.py file with the following code:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!" 

This app does a few things:

  • Imports the Flask class
  • Creates a Flask instance called app
  • Uses the @app.route decorator to map the / path to the hello() function
  • Returns "Hello World!" text when someone visits the website root at /

To run the application locally, set an environment variable and run Flask‘s built-in server:

export FLASK_APP=app.py
flask run

Visit http://localhost:5000 in your browser, and you should see the "Hello World!" displayed!

Press CTRL+C to stop the server when you are done testing.

While great for testing locally, this server won‘t work for deploying publicly. We‘ll set up a production WSGI server later to fix that.

Project Structure and Routing

For anything more than a trivial application, we‘ll want to structure our code better. Here is an improved structure:

/project
    /app
        __init__.py
        routes.py
        templates/
        static/
    run.py

The __init__.py file initialized Flask, the routes.py file contains the different app routes, templates/ contains Jinja templates, and static/ contains CSS/JS assets.

The run.py script will run the app using a production WSGI server (Gunicorn in this case).

Here is what each file needs to have:

init.py:

from flask import Flask

app = Flask(__name__)

import app.routes

This creates the Flask instance like before but refers to the routes file.

routes.py:

from app import app 

@app.route("/")
def index():
    return "Hello World!"

@app.route("/about") 
def about():
    return "About me"

Contains the route decorated functions.

run.py:

from app import app

if __name__ == "__main__":
    app.run()

Creates a entry point to run Gunicorn.

We can now reference multiple routes like / and /about to display different pages. Run the server with flask run and try visiting the URLs!

Serving HTML Files

While returning plain text from our route functions works, for actual web content we need to serve HTML.

Flask makes this very simple using a render_template shortcut.

Create an index.html template inside templates/:

<!DOCTYPE html>
<html>
<head>
  <title>Home Page</title>
</head>
<body>

</body>
</html> 

Update the index() route to use this template:

from flask import render_template

@app.route("/")
def index():
    return render_template(‘index.html‘)

Flask will automatically detect and render the HTML templates. Restart the server and load the homepage, and you should see the rendered "Welcome" message!

We can use the same method to also serve an about.html page at the /about route.

Adding Static Assets

Every website commonly needs static assets – CSS and JavaScript files for styling/interactivity.

First, create the files:

static/styles.css:

body {
  background-color: lightblue;
} 

static/main.js:

alert("Welcome!");

Include the assets in Jinja templates like so:

templates/base.html:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="{{ url_for(‘static‘, filename=‘styles.css‘) }}">
  </head>
  <body>
    {% block content%}{% endblock %}
    <script src="{{ url_for(‘static‘, filename=‘main.js‘) }}"></script>
  </body>
</html>

templates/index.html:

{% extends "base.html" %}

{% block content %}

{% endblock %}

This templates all inherit from base.html. The url_for() helper generates the static file URL path automatically.

Reload the homepage, and your site is now loaded with a CSS stylesheet for styling and JavaScript for client-side functionality! The assets are served correctly as static files separate from the main HTML.

Database Integration

Most web apps rely on data persistence in a database. For a small Flask application, SQLite is the easiest database to integrate.

First, create the database model class:

/app/models.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)

    def __repr__(self):
        return f"<User {self.username}>"

This creates a simple User table with columns for ID and username using SQLAlchemy, Flask‘s preferred ORM.

In init.py, initialize SQLAlchemy:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
db = SQLAlchemy(app)

from app import routes, models

Now we can query User records in our route functions:

routes.py:

@app.route(‘/users‘)
def users():
    users = User.query.all()  
    return  render_template(‘users.html‘, users=users)

And display them:

users.html:



{% for user in users %}
<div>{{user.username}}</div>
{% endfor %}

While Flask makes integrating SQLite databases a breeze, for serious applications consider using PostgreSQL or MySQL instead for better performance and scalability.

Form Handling

User input is integral to most web applications. Form handling in Flask is powered by the WTForms library.

Here is how to create a simple contact form:

forms.py:

from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField

class ContactForm(FlaskForm):

    name = StringField(‘Name‘)
    email = StringField(‘Email‘)
    message = TextAreaField(‘Message‘)
    submit = SubmitField(‘Submit‘)

This form has input fields for name, email, a message box and a submit button.

Handling form submissions takes just a few lines of code:

routes.py:

from app.forms import ContactForm

@app.route(‘/contact‘, methods=[‘GET‘, ‘POST‘])
def contact():
    form = ContactForm()

    if form.validate_on_submit(): 

        # Form submission logic
        print(form.name.data)
        print(form.email.data)
        print(form.message.data)

        form.name.data = ‘‘  
        form.email.data = ‘‘
        form.message.data = ‘‘

        return render_template(‘contact.html‘, msg=‘Message sent!‘, form=form)

    return render_template(‘contact.html‘, form=form)

If the HTTP method is POST, form data will be validated and we can process it before reloading the page with a success message. Pretty painless!

Flask simplifies other common web development tasks like sending emails, implementing user authentication, handling file uploads etc. with myriad extensions.

Set Up Gunicorn

To deploy online, we need our Flask app to integrate with a production WSGI server instead of the default test server.

Gunicorn is a great Python WSGI server for small to medium-sized sites handling moderate traffic.

Install Gunicorn:

pip install gunicorn

Instead of flask run, we will start up the app using Gunicorn.

In run.py, add:

import os
from app import app 

if __name__ == "__main__":
    HOST = os.environ.get(‘SERVER_HOST‘, ‘localhost‘)
    try:
        PORT = int(os.environ.get(‘SERVER_PORT‘, ‘5555‘))
    except ValueError:
        PORT = 5555
    app.run(HOST, PORT)

Run Gunicorn from your terminal:

gunicorn --bind 0.0.0.0:5000 run:app

This starts the app on port 5000 using the Gunicorn WSGI server instead of Flask‘s default.

The app should work just like previously! Except now, it is production-ready.

For heavy workloads and scaling, consider switching from Gunicorn to more advanced WSGI servers like uWSGI or Waitress.

Host on Heroku

We can host our Flask application online using Heroku‘s free plan for low traffic sites.

Make sure the app is committed to a Git repository first. Then create a Procfile containing:

web: gunicorn run:app

Commit again and push these changes.

Next, go to Heroku and create a new app. Connect your Github repository to automatically deploy from master.

Enable automatic deploys in your Heroku app‘s Deploy section to continously deploy each Git push. You may also need to scale the web dynos:

heroku ps:scale web=1  

Within minutes, your Flask website should be up and running on the live Heroku URL!

While Heroku makes app hosting and deployment simple, for more flexibility consider cloud servers like DigitalOcean droplets configured manually with Flask and Gunicorn.

Custom Domain Setup

To use a custom domain instead of the default Heroku URL do the following:

  1. Add a domain from your DNS provider under Heroku Settings > Custom Domains

  2. Enable Automatic Certificate Management or manually upload an SSL/TLS certificate to use HTTPS

  3. Configure DNS records like A, AAAA, and CNAME to point to Heroku

For example, create an A record pointing @ to the Heroku IP address. And a CNAME record for www pointing to the Heroku app URL.

After DNS propagates, your custom domain name will display the Flask app!

Recap and Next Steps

Let‘s recap what we built so far:

  • A Flask app set up using Model-View-Controller conventions
  • Routes and views to display HTML templates
  • Static files serving CSS and JavaScript
  • An integrated SQLite database
  • Form handling logic
  • Gunicorn WSGI server
  • Free hosting on Heroku with continuous delivery

This covers the foundations you need to build almost any basic website – with users, data persistence, styling and functionality.

Where to go from here? Here are some ideas:

  • Add user authentication
  • Implement profiles and content posting
  • Develop a REST API for mobile apps
  • Create an online store with shopping carts
  • Build an interactive data dashboard
  • Add comments, forums and discussions

Flask is flexible enough to handle all these and more! The only limit is your imagination.

We just scratched the surface of what‘s possible by building websites in Python. There is a whole world of web development for you to explore with Flask.

Similar Posts