Skip to content

Latest commit

 

History

History
437 lines (338 loc) · 10.2 KB

File metadata and controls

437 lines (338 loc) · 10.2 KB

1.2 Web 框架入门

📖 概述

Web 框架是构建 Web 应用的基础工具,它们提供了处理 HTTP 请求、路由管理、模板渲染等核心功能。本章将介绍主流的 Python Web 框架,重点学习 Flask 和 FastAPI。

🌐 Web 框架简介

什么是 Web 框架

Web 框架是一个软件框架,用于简化 Web 应用程序、Web 服务和 Web 站点的开发。它提供了一套标准化的方法来构建和部署 Web 应用。

Web 框架的作用

  • 路由管理:将 URL 映射到处理函数
  • 请求处理:解析 HTTP 请求参数
  • 响应生成:生成 HTTP 响应
  • 模板渲染:渲染 HTML 页面
  • 数据库集成:提供数据库操作接口
  • 安全防护:处理认证、授权、CSRF 等

🏗️ 主流 Python Web 框架

框架对比

框架 特点 适用场景 学习难度
Flask 轻量级、灵活 小型项目、原型开发 简单
FastAPI 现代、高性能、自动文档 API 开发、微服务 中等
Django 全功能、企业级 大型项目、内容管理 复杂
Tornado 异步、高性能 实时应用、长连接 复杂

选择建议

  • 初学者:从 Flask 开始,学习基础概念
  • API 开发:选择 FastAPI,享受现代特性
  • 企业项目:考虑 Django,获得完整生态
  • 高性能需求:评估 Tornado 或 FastAPI

🚀 Flask 基础

安装和配置

# 安装 Flask
pip install flask

# 创建虚拟环境(推荐)
python -m venv venv
source venv/bin/activate  # Linux/Mac
# venv\Scripts\activate  # Windows

第一个 Flask 应用

from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello, World!'

@app.route('/about')
def about():
    return 'About Page'

@app.route('/api/users')
def get_users():
    users = [
        {'id': 1, 'name': '张三'},
        {'id': 2, 'name': '李四'}
    ]
    return jsonify(users)

@app.route('/user/<int:user_id>')
def get_user(user_id):
    return f'User ID: {user_id}'

if __name__ == '__main__':
    app.run(debug=True)

路由和视图函数

# 基本路由
@app.route('/')
def index():
    return 'Index Page'

# 带参数的路由
@app.route('/user/<username>')
def show_user(username):
    return f'User: {username}'

# 指定 HTTP 方法
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        # 处理登录逻辑
        return 'Login successful'
    return render_template('login.html')

# 带类型转换的路由
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post ID: {post_id}'

请求和响应

from flask import request, jsonify, make_response

@app.route('/api/data', methods=['POST'])
def handle_data():
    # 获取请求数据
    data = request.get_json()
    name = data.get('name', '')
    
    # 处理数据
    result = {'message': f'Hello, {name}!', 'status': 'success'}
    
    # 返回 JSON 响应
    return jsonify(result)

@app.route('/custom-response')
def custom_response():
    response = make_response('Custom Response')
    response.headers['Content-Type'] = 'text/plain'
    response.status_code = 200
    return response

模板渲染

from flask import render_template

@app.route('/profile/<username>')
def profile(username):
    user_info = {
        'name': username,
        'email': f'{username}@example.com',
        'age': 25
    }
    return render_template('profile.html', user=user_info)

templates/profile.html:

<!DOCTYPE html>
<html>
<head>
    <title>用户资料</title>
</head>
<body>
    <h1>{{ user.name }} 的资料</h1>
    <p>邮箱: {{ user.email }}</p>
    <p>年龄: {{ user.age }}</p>
</body>
</html>

⚡ FastAPI 入门

安装和配置

# 安装 FastAPI 和 ASGI 服务器
pip install fastapi uvicorn

# 安装可选依赖
pip install fastapi[all]

第一个 FastAPI 应用

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(title="My API", version="1.0.0")

# 数据模型
class User(BaseModel):
    id: int
    name: str
    email: str
    age: Optional[int] = None

class UserCreate(BaseModel):
    name: str
    email: str
    age: Optional[int] = None

# 路由
@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/users", response_model=List[User])
async def get_users():
    users = [
        User(id=1, name="张三", email="zhangsan@example.com", age=25),
        User(id=2, name="李四", email="lisi@example.com", age=30)
    ]
    return users

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    # 模拟数据库查询
    user = User(id=user_id, name="张三", email="zhangsan@example.com", age=25)
    return user

@app.post("/users", response_model=User)
async def create_user(user: UserCreate):
    # 模拟创建用户
    new_user = User(id=3, **user.dict())
    return new_user

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

数据验证和序列化

from pydantic import BaseModel, EmailStr, validator
from typing import Optional
from datetime import datetime

class User(BaseModel):
    id: int
    name: str
    email: EmailStr
    age: Optional[int] = None
    created_at: datetime = datetime.now()
    
    @validator('age')
    def validate_age(cls, v):
        if v is not None and (v < 0 or v > 150):
            raise ValueError('年龄必须在 0-150 之间')
        return v
    
    class Config:
        schema_extra = {
            "example": {
                "id": 1,
                "name": "张三",
                "email": "zhangsan@example.com",
                "age": 25
            }
        }

依赖注入

from fastapi import Depends, HTTPException, status
from typing import Optional

# 模拟数据库
fake_users_db = {
    "user1": {"username": "user1", "full_name": "User One"},
    "user2": {"username": "user2", "full_name": "User Two"},
}

def get_user(username: str):
    if username in fake_users_db:
        return fake_users_db[username]
    return None

@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_user)):
    if current_user is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return current_user

中间件和异常处理

from fastapi import Request
import time

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

@app.exception_handler(404)
async def not_found_handler(request: Request, exc: HTTPException):
    return {"message": "资源未找到", "path": request.url.path}

🔄 框架对比与选择

Flask vs FastAPI

特性 Flask FastAPI
性能 中等 高性能
异步支持 有限 原生支持
自动文档 需要插件 内置
类型提示 可选 强制
学习曲线 简单 中等
生态系统 丰富 新兴

选择建议

  1. 选择 Flask 的场景

    • 学习 Web 开发基础
    • 快速原型开发
    • 简单的 Web 应用
    • 需要大量第三方扩展
  2. 选择 FastAPI 的场景

    • 构建现代 API
    • 需要高性能
    • 团队重视类型安全
    • 需要自动生成文档

💻 实践练习

练习 1:Flask 待办事项应用

from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

# 简单的内存存储
todos = []

@app.route('/')
def index():
    return render_template('index.html', todos=todos)

@app.route('/add', methods=['POST'])
def add_todo():
    todo = request.form.get('todo')
    if todo:
        todos.append({'id': len(todos) + 1, 'text': todo, 'done': False})
    return redirect(url_for('index'))

@app.route('/toggle/<int:todo_id>')
def toggle_todo(todo_id):
    for todo in todos:
        if todo['id'] == todo_id:
            todo['done'] = not todo['done']
            break
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True)

练习 2:FastAPI 用户管理 API

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

app = FastAPI()

class User(BaseModel):
    id: int
    name: str
    email: str

class UserCreate(BaseModel):
    name: str
    email: str

# 模拟数据库
users_db = []
user_id_counter = 1

@app.post("/users", response_model=User)
async def create_user(user: UserCreate):
    global user_id_counter
    new_user = User(id=user_id_counter, **user.dict())
    users_db.append(new_user)
    user_id_counter += 1
    return new_user

@app.get("/users", response_model=List[User])
async def get_users():
    return users_db

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    for user in users_db:
        if user.id == user_id:
            return user
    raise HTTPException(status_code=404, detail="User not found")

📚 学习资源

官方文档

推荐阅读

🔍 知识检查

完成本节学习后,请检查是否掌握:

  • 理解 Web 框架的作用和特点
  • 能够创建简单的 Flask 应用
  • 掌握 Flask 的路由和视图函数
  • 能够创建 FastAPI 应用
  • 理解数据验证和依赖注入
  • 能够选择合适的 Web 框架

上一节1.1 HTTP 协议基础 | 下一节1.3 前后端交互