Navigation
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
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.
Full-featured, admin interface, built-in ORM, authentication, and extensive middleware. Best for large applications requiring rapid development with built-in security features.
Lightweight and flexible microframework. Minimal core with extensions for nearly everything — perfect for microservices, learning, and projects requiring fine-grained control.
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.
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
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.
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']}")
03 — Microframework
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.
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")
04 — Templating
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).
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)
Advertisement
05 — Input Handling
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.
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}")
06 — ORM
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.
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()}")
07 — Full-Stack Framework
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.
# 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")
Advertisement
08 — Modern APIs
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.
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")
09 — Production
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.
python-decouple or python-dotenv to load configuration from .env files.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.")
🧠 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
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.
Get new Python tutorials, web development guides, and code deep-dives delivered to your inbox.
Join readers learning Python & web development.
Community
Comments