PYTHON WEB DEV · 2026

Web Development in Python:
Flask, Django & FastAPI

A complete, hands-on guide to Python web development. Covers Flask microservices, Django's batteries-included architecture, FastAPI's async REST APIs, SQLAlchemy ORM, Jinja2 templating, and WTForms validation — with fully runnable in-browser code examples powered by Pyodide.

Advertisement

01 — Overview

Python Web Development Landscape

frameworks and ecosystems

Python offers a rich ecosystem of web frameworks, each designed for a different philosophy and scale. Django follows the "batteries included" approach, providing a full-stack solution with built-in ORM, admin interface, authentication, and templating. Flask is a minimal microframework that gives you full control — ideal for microservices, APIs, and learning the fundamentals. FastAPI is the modern choice, built on Python type hints with native async support and automatic OpenAPI documentation generation.

Choosing the right framework depends on your project's size, performance requirements, and your team's preferences. All three frameworks share Python's readability and the same underlying HTTP protocol, making it straightforward to migrate or combine them in a microservices architecture.

🏛️ Django

Full-featured, admin interface, built-in ORM, authentication, and extensive middleware. Best for large applications requiring rapid development with built-in security features.

⚗️ Flask

Lightweight and flexible microframework. Minimal core with extensions for nearly everything — perfect for microservices, learning, and projects requiring fine-grained control.

⚡ FastAPI

Modern async framework with automatic OpenAPI docs, Pydantic validation, and exceptional performance rivaling Node.js and Go. The best choice for high-performance REST APIs.

🎨 Jinja2

Powerful templating engine used by Flask and Django. Supports variables, loops, conditionals, template inheritance, and macros for building dynamic HTML with clean separation of concerns.

Advertisement

02 — Protocol

HTTP & Requests in Python

understanding the protocol

HTTP (HyperText Transfer Protocol) is the foundation of all web communication. Every web framework you use is ultimately an abstraction over HTTP. Understanding the core concepts — methods, status codes, headers, and the request/response cycle — makes you a more effective web developer regardless of the framework you choose.

Python's requests library is the de facto standard for making HTTP calls. It abstracts away the complexity of the underlying urllib module while providing a clean, human-friendly API. The library handles redirects, sessions, authentication, and JSON serialization automatically.

python · requests
import requests

response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
print(f"Status: {response.status_code}")
data = response.json()
print(f"Title: {data['title']}")
print(f"Body: {data['body'][:60]}...")

new_post = {'title': 'python web', 'body': 'flask is great', 'userId': 1}
post_response = requests.post('https://jsonplaceholder.typicode.com/posts', json=new_post)
print(f"Created post ID: {post_response.json()['id']}")
[output will appear here after clicking Run]

03 — Microframework

Flask Fundamentals

minimal web application

Flask is a WSGI microframework that gives you the essentials and nothing more. A minimal application fits in under ten lines. Route decorators map URLs to Python functions called view functions. Flask handles the HTTP parsing, routing, and response formatting — you focus entirely on your application logic.

Flask's extension ecosystem covers everything missing from the core: Flask-SQLAlchemy for databases, Flask-WTF for forms, Flask-Login for authentication, and Flask-RESTful for API building. This modular architecture means you only add what you actually need.

python · flask
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/')
def home():
    return "Python Blue & Obsidian — Flask App"

@app.route('/api/data')
def get_data():
    return jsonify({'framework': 'flask', 'theme': 'python blue', 'version': '3.1'})

@app.route('/api/users/<int:user_id>')
def get_user(user_id):
    return jsonify({'id': user_id, 'name': f'user_{user_id}'})

print("Flask app defined.")
print("Routes: / and /api/data and /api/users/<id>")
print("Run: flask run  or  python app.py")
[Flask app structure — would serve at http://127.0.0.1:5000]

04 — Templating

Jinja2 Templates

dynamic HTML generation

Jinja2 is the default templating engine for Flask and is also used by Django (with slight syntax differences). It allows you to embed Python-like logic — variables, loops, conditionals, and template inheritance — directly into HTML files. This creates a clean separation between your application logic and presentation layer.

The template inheritance system is particularly powerful: define a base layout with blocks, then extend it in child templates. This eliminates HTML duplication across pages and keeps your front-end DRY (Don't Repeat Yourself).

python · jinja2
from jinja2 import Template

template_str = """
<!DOCTYPE html>
<html>
<head><title>{{ title }}</title></head>
<body>
  <h1>{{ heading }}</h1>
  <ul>
  {% for item in items %}
    <li>{{ item }}</li>
  {% endfor %}
  </ul>
</body>
</html>
"""

template = Template(template_str)
rendered = template.render(
    title="python web",
    heading="flask + jinja2",
    items=["python blue", "obsidian dark", "interactive code"]
)
print(rendered)
[rendered HTML will appear here]

Advertisement

05 — Input Handling

Forms & Validation (WTForms)

handling user input securely

Flask-WTF provides seamless integration with WTForms for secure, declarative form handling. Forms are defined as Python classes, with each field declared as a class attribute. Built-in validators cover common cases — required fields, email format, string length, numeric ranges — while custom validators handle business-specific rules.

CSRF (Cross-Site Request Forgery) protection is enabled by default through Flask-WTF's FlaskForm base class. This adds a hidden token to every form that Flask validates on submission, protecting against a common web vulnerability with zero extra code.

python · wtforms
from wtforms import Form, StringField, PasswordField, IntegerField
from wtforms.validators import DataRequired, Email, Length, NumberRange

class RegistrationForm(Form):
    username  = StringField('Username', validators=[DataRequired(), Length(min=3, max=25)])
    email     = StringField('Email', validators=[DataRequired(), Email()])
    password  = PasswordField('Password', validators=[DataRequired(), Length(min=8)])
    age       = IntegerField('Age', validators=[DataRequired(), NumberRange(min=13, max=120)])

class MockRequest:
    def __init__(self, data):
        self.form = data
        self.method = 'POST'

form_data = {'username': 'glenn', 'email': 'glenn@example.com', 'password': 'securepass', 'age': '28'}
form = RegistrationForm(data=form_data)
print(f"Form valid: {form.validate()}")
print(f"Fields: username={form.username.data}, email={form.email.data}")
print(f"Errors: {form.errors}")
[form validation output will appear here]

06 — ORM

Databases & SQLAlchemy

ORM for Python

SQLAlchemy is Python's most powerful and mature ORM. It bridges the gap between your Python object model and the relational database world. Models are defined as Python classes that inherit from a declarative base — SQLAlchemy automatically generates the SQL for table creation, inserts, queries, and relationships.

The ORM supports all major database engines — SQLite for development, PostgreSQL for production, MySQL, and others — with near-zero code changes when switching. Advanced features include lazy loading, eager loading, relationship back-references, and hybrid properties that compute values from both Python and SQL.

python · sqlalchemy
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.orm import declarative_base, sessionmaker
from datetime import datetime

engine = create_engine('sqlite:///:memory:')
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id         = Column(Integer, primary_key=True)
    username   = Column(String(50), unique=True, nullable=False)
    email      = Column(String(120), unique=True)
    created_at = Column(DateTime, default=datetime.utcnow)

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

Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

session.add_all([
    User(username='glenn', email='glenn@valleysbytes.dev'),
    User(username='alice', email='alice@example.com'),
])
session.commit()

users = session.query(User).all()
for u in users:
    print(f"User: {u.username} — {u.email}")
print(f"Total users: {session.query(User).count()}")
[SQLAlchemy in-memory DB output will appear here]

07 — Full-Stack Framework

Django Basics

batteries-included framework

Django follows the "batteries included" philosophy — everything you need for a production web application is built in: a powerful ORM, admin interface, authentication system, URL routing, form handling, template engine, and security middleware. This makes Django an exceptionally fast choice for teams building feature-rich applications.

Django's MTV architecture (Model-Template-View) maps cleanly onto the web: Models define your data structure, Templates render HTML, and Views contain the business logic connecting them. The auto-generated admin interface alone can save days of development for internal tools.

python · django
# models.py — Django model definition
from django.db import models

class BlogPost(models.Model):
    title     = models.CharField(max_length=200)
    content   = models.TextField()
    published = models.DateTimeField(auto_now_add=True)
    author    = models.ForeignKey('auth.User', on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-published']

# views.py — View function using the model
from django.shortcuts import render
from .models import BlogPost

def post_list(request):
    posts = BlogPost.objects.all().order_by('-published')
    return render(request, 'blog/list.html', {'posts': posts})

print("Django model BlogPost defined with author ForeignKey.")
print("Run: python manage.py makemigrations && python manage.py migrate")
print("Admin: python manage.py createsuperuser")
[Django structure — requires a Django environment to execute]

Advertisement

08 — Modern APIs

REST APIs with FastAPI

modern, async, type hints

FastAPI is built on Starlette (ASGI framework) and Pydantic (data validation). It leverages Python type hints to automatically generate request validation, serialization, and interactive OpenAPI documentation at /docs. This eliminates an entire category of boilerplate code found in Flask or Django REST framework.

FastAPI's async support means a single worker can handle thousands of concurrent connections without threads, making it ideal for I/O-bound workloads like database queries and external API calls. Benchmark tests consistently place it among the fastest Python web frameworks, comparable to Node.js and Go.

python · fastapi
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(title="Python Blue API", version="1.0")

class Item(BaseModel):
    name:  str
    price: float
    tags:  List[str] = []
    in_stock: Optional[bool] = True

items_db: List[Item] = []

@app.post("/items/", response_model=Item)
async def create_item(item: Item):
    items_db.append(item)
    return item

@app.get("/items/", response_model=List[Item])
async def read_items():
    return items_db

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id >= len(items_db):
        raise HTTPException(status_code=404, detail="Item not found")
    return items_db[item_id]

print("FastAPI app with Pydantic models defined.")
print("Run: uvicorn main:app --reload")
print("Interactive API docs: http://localhost:8000/docs")
[FastAPI structure — run with uvicorn for a live server]

09 — Production

Deployment & Best Practices

taking your app to production

Deploying a Python web application involves several key considerations: choosing a WSGI/ASGI server, containerization with Docker, environment variable management, database migrations, and static file serving. Each framework has a recommended production stack.

shell · deployment
import subprocess, sys

commands = [
    "pip install flask gunicorn flask-sqlalchemy flask-migrate python-decouple",
    "gunicorn --workers 4 --bind 0.0.0.0:8000 wsgi:app",
    "uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4",
]

print("=== Python Web Deployment Checklist ===")
print()
print("1. Install production server:")
print("   pip install gunicorn uvicorn[standard]")
print()
print("2. Set environment variables in .env:")
print("   SECRET_KEY=your-secret-key-here")
print("   DATABASE_URL=postgresql://user:pass@localhost/dbname")
print("   DEBUG=False")
print()
print("3. Run with Gunicorn (Flask/Django):")
print("   gunicorn --workers 4 --bind 0.0.0.0:8000 wsgi:app")
print()
print("4. Run with Uvicorn (FastAPI):")
print("   uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4")
print()
print("5. Nginx config (reverse proxy to port 8000)")
print("   proxy_pass http://127.0.0.1:8000;")
print()
print("Deployment checklist complete.")
[deployment checklist will appear here]

🧠 Python web stack summary: Use Flask for learning and microservices, Django for feature-complete applications with built-in admin, and FastAPI for high-performance async APIs. All frameworks benefit from PostgreSQL in production, Gunicorn/Uvicorn as application servers, Nginx as a reverse proxy, and Docker for containerization.

FAQ

Frequently Asked Questions

Start with Flask if you want to understand web fundamentals from the ground up — it gives you full control with minimal magic. Choose Django if you need a production-ready application quickly, as it provides built-in admin, ORM, authentication, and templating. For APIs specifically, FastAPI is the modern choice with automatic documentation and type hints.

SQLAlchemy is Python's most powerful ORM (Object Relational Mapper). It lets you define database tables as Python classes, write queries in Python instead of raw SQL, and switch between database engines (SQLite, PostgreSQL, MySQL) with minimal code changes. Flask-SQLAlchemy integrates it seamlessly into Flask applications.

FastAPI is built on Starlette and Pydantic, offering native async/await support, automatic OpenAPI documentation at /docs, and request validation via Python type hints. It is significantly faster than Flask for I/O-bound workloads and eliminates boilerplate validation code, while Django excels at full-stack applications requiring admin interfaces and built-in authentication.

Use Flask-Login for session-based authentication and Flask-JWT-Extended for token-based authentication in APIs. Flask-Login manages user sessions, the "remember me" feature, and provides the @login_required decorator. Always hash passwords with werkzeug.security or bcrypt — never store plain text.

Yes — Pyodide (as used in this page) runs Python in the browser via WebAssembly. PyScript lets you write Python directly in HTML. For production SPAs, frameworks like Reflex and Streamlit let you build full-stack apps in pure Python. However, JavaScript frameworks (React, Vue) remain the dominant choice for complex interactive UIs.

Click a platform above to generate an AI-crafted caption tailored for that network.

Community

Comments

0 comments

Be the first to comment! 👋

Stay in the Loop

Get new Python tutorials, web development guides, and code deep-dives delivered to your inbox.

No spam Free forever Unsubscribe anytime

Join readers learning Python & web development.