Python 数据库实战:SQLite、PostgreSQL、SQLAlchemy 与 ORM 完全指南

Python 数据库开发完全指南:SQLite 快速上手、PostgreSQL/MySQL 连接、SQLAlchemy ORM 模型定义与查询、asyncpg 异步数据库访问、Alembic 迁移工具。从简单脚本到生产级数据库应用的全栈实践。

几乎所有 Python 应用都需要持久化数据。本文从 SQLite 起步,到 SQLAlchemy ORM,再到异步数据库访问,给你一个完整的数据库技术栈。


目录

  1. 数据库选型指南
  2. SQLite:零配置数据库
  3. PostgreSQL 与 psycopg2
  4. SQLAlchemy ORM 核心
  5. 关系与查询
  6. 异步数据库:asyncpg
  7. 数据库迁移:Alembic
  8. 生产环境最佳实践

1. 数据库选型指南

数据库适用场景Python 驱动
SQLite单机应用、测试、嵌入式sqlite3(内置)
PostgreSQL生产应用、复杂查询psycopg2, asyncpg
MySQLWeb 应用、LAMP 栈PyMySQL, mysqlclient
MongoDB文档型数据pymongo
Redis缓存、消息队列redis-py

2. SQLite:零配置数据库

2.1 基础 CRUD

import sqlite3
from pathlib import Path

DB_PATH = Path("app.db")

def init_db():
    with sqlite3.connect(DB_PATH) as conn:
        conn.execute("""
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT UNIQUE,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)

def add_user(name: str, email: str):
    with sqlite3.connect(DB_PATH) as conn:
        conn.execute("INSERT INTO users (name, email) VALUES (?, ?)", (name, email))
        conn.commit()

def get_users():
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row   # 返回字典式结果
        return conn.execute("SELECT * FROM users").fetchall()

# 使用
init_db()
add_user("Alice", "alice@example.com")
for user in get_users():
    print(dict(user))

2.2 SQLite 高级特性

# 事务控制
with sqlite3.connect(DB_PATH) as conn:
    try:
        conn.execute("INSERT INTO users (name) VALUES (?)", ("Bob",))
        conn.execute("INSERT INTO invalid_table ...")   # 会失败
        conn.commit()
    except sqlite3.Error:
        conn.rollback()

# 返回字典结果
conn.row_factory = lambda c, r: {col[0]: r[idx] for idx, col in enumerate(c.description)}

# FTS5 全文搜索(需要编译时启用)
conn.execute("CREATE VIRTUAL TABLE docs USING fts5(title, content)")

3. PostgreSQL 与 psycopg2

# pip install psycopg2-binary
import psycopg2
from psycopg2.extras import RealDictCursor

conn = psycopg2.connect(
    host="localhost",
    database="mydb",
    user="myuser",
    password="mypass",
)

with conn.cursor(cursor_factory=RealDictCursor) as cur:
    cur.execute("SELECT * FROM users WHERE age > %s", (18,))
    for row in cur.fetchall():
        print(dict(row))

conn.close()

4. SQLAlchemy ORM 核心

4.1 模型定义

# pip install sqlalchemy
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from datetime import datetime

Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)
    email = Column(String(255), unique=True)
    created_at = Column(DateTime, default=datetime.utcnow)
    
    posts = relationship("Post", back_populates="author")

class Post(Base):
    __tablename__ = "posts"
    
    id = Column(Integer, primary_key=True)
    title = Column(String(200), nullable=False)
    content = Column(String)
    author_id = Column(Integer, ForeignKey("users.id"))
    
    author = relationship("User", back_populates="posts")

# 创建表
engine = create_engine("sqlite:///app.db", echo=True)
Base.metadata.create_all(engine)

# Session
Session = sessionmaker(bind=engine)

4.2 CRUD 操作

# 创建
with Session() as session:
    user = User(name="Alice", email="alice@example.com")
    session.add(user)
    session.commit()
    print(user.id)   # 自动获取自增 ID

# 查询
with Session() as session:
    # 主键查询
    user = session.get(User, 1)
    
    # 条件查询
    users = session.query(User).filter(User.name.like("A%")).all()
    
    # 分页
    page = session.query(User).offset(10).limit(10).all()

# 更新
with Session() as session:
    user = session.get(User, 1)
    user.name = "New Name"
    session.commit()

# 删除
with Session() as session:
    user = session.get(User, 1)
    session.delete(user)
    session.commit()

5. 关系与查询

5.1 关联查询

# 一对多:用户 - 文章
with Session() as session:
    user = session.get(User, 1)
    for post in user.posts:
        print(post.title)

# 预加载(避免 N+1 查询)
from sqlalchemy.orm import joinedload

users = session.query(User).options(joinedload(User.posts)).all()

# 聚合查询
from sqlalchemy import func

result = session.query(
    User.name,
    func.count(Post.id).label("post_count")
).join(Post).group_by(User.id).all()

6. 异步数据库:asyncpg

# pip install asyncpg
import asyncpg
import asyncio

async def main():
    conn = await asyncpg.connect("postgresql://user:pass@localhost/db")
    
    # 查询
    rows = await conn.fetch("SELECT * FROM users WHERE age > $1", 18)
    for row in rows:
        print(row["name"])
    
    # 事务
    async with conn.transaction():
        await conn.execute("INSERT INTO users (name) VALUES ($1)", "Bob")
    
    await conn.close()

asyncio.run(main())

SQLAlchemy 异步版本

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

async_engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
AsyncSessionLocal = sessionmaker(async_engine, class_=AsyncSession)

async def get_users():
    async with AsyncSessionLocal() as session:
        result = await session.execute(select(User).where(User.age > 18))
        return result.scalars().all()

7. 数据库迁移:Alembic

# 安装
pip install alembic

# 初始化
alembic init migrations

# 修改 alembic.ini → sqlalchemy.url = postgresql://user:pass@localhost/db
# 修改 migrations/env.py → 导入你的 Base

# 生成迁移脚本
alembic revision --autogenerate -m "create users table"

# 升级
alembic upgrade head

# 降级
alembic downgrade -1

8. 生产环境最佳实践

  • 使用连接池(SQLAlchemy 内置)
  • 敏感信息存环境变量
  • 索引外键列
  • 定期备份(pg_dump、mysqldump)
  • 查询慢日志分析

延伸阅读


数据库是应用的根基。从 SQLite 的快速原型到 PostgreSQL 的生产部署,SQLAlchemy 让你用同一套 API 驾驭不同数据库。掌握 ORM 的查询优化和迁移管理,是 Python 后端工程师的核心能力。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「python」更多文章

  1. Python 高级异步编程:Trio 结构化并发与 AnyIO 兼容层
  2. Python 数据工程与 ETL 管道实战
  3. Python 元编程与动态特性深度解析