MongoDB 与 SQLAlchemy ORM
本教程共 70 篇 · 第 62 篇 · 更新于 2026-07-22 · 约 6 分钟阅读
62. MongoDB 与 SQLAlchemy ORM
本节目标:学会用 PyMongo 操作 MongoDB,理解 ORM 的概念,掌握 SQLAlchemy 的基础 CRUD。
关系型数据库(如 MySQL)用表格存数据,结构严格;NoSQL 数据库(如 MongoDB)用文档存数据,灵活自由。ORM 则让你用操作对象的方式代替手写 SQL。这节把两种风格都讲一遍,开阔你的选型视野。
MongoDB:灵活的文档数据库
MongoDB 以 BSON(二进制 JSON)格式存储数据,一条记录就是一个文档,文档组成集合,集合组成数据库。没有固定的表结构,非常适合需求变化快的项目。
安装与连接
pip install pymongo
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
db = client['testdb']
collection = db['users']
如果 MongoDB 开启了认证,连接字符串里带上用户名密码:
mongodb://username:password@localhost:27017/testdb
增删改查
插入文档:
user = {'name': 'Alice', 'age': 30, 'skills': ['Python', 'MongoDB']}
result = collection.insert_one(user)
print(f"插入 ID: {result.inserted_id}")
collection.insert_many([
{'name': 'Bob', 'age': 25},
{'name': 'Charlie', 'age': 35}
])
MongoDB 自动给每条文档生成 _id 字段,类型是 ObjectId。你也可以自己指定。
查询文档:
# 查一条
alice = collection.find_one({'name': 'Alice'})
print(alice)
# 查多条
for doc in collection.find({'age': {'$gt': 25}}):
print(doc)
# 排序 + 限制
for doc in collection.find().sort('age', -1).limit(2):
print(doc)
$gt 表示大于(greater than),类似的还有 $lt、$gte、$lte、$ne、$in 等。条件查询的语法是字典嵌字典,刚开始可能不习惯,多写几次就顺手了。
更新和删除:
collection.update_one(
{'name': 'Alice'},
{'$set': {'age': 31, 'city': 'Beijing'}}
)
collection.delete_one({'name': 'Bob'})
collection.delete_many({'age': {'$lt': 26}})
$set 只更新指定字段,不会覆盖整个文档。如果不用 $set,update_one 会用新文档替换旧文档。
Warning
delete_many和update_many影响范围很大,生产环境执行前先用find()确认条件是否正确,避免误删误改。
SQLAlchemy:用 Python 对象操作数据库
写原生 SQL 很自由,但代码里字符串和逻辑混在一起,维护起来头疼。ORM(Object-Relational Mapping)把数据库表映射成 Python 类,把记录映射成对象,让你用面向对象的方式操作数据。
Note本节使用 SQLAlchemy 1.x 风格代码。SQLAlchemy 2.0+ 推荐使用
select()+session.execute()新风格,若你使用的是新版本,建议查阅官方迁移指南。
SQLAlchemy 是 Python 世界里最成熟的 ORM,支持 MySQL、PostgreSQL、SQLite 等多种数据库。
安装与连接
pip install sqlalchemy pymysql
from sqlalchemy import create_engine
# SQLite
engine = create_engine('sqlite:///test.db', echo=True)
# MySQL
# engine = create_engine('mysql+pymysql://user:password@localhost/testdb')
echo=True 会在控制台打印生成的 SQL,方便学习和调试。
定义模型
from sqlalchemy.orm import declarative_base, sessionmaker
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
age = Column(Integer)
Base.metadata.create_all(engine)
declarative_base()创建基类,所有模型都继承它。Column定义字段,Integer、String等指定类型。create_all()根据模型自动建表,表已存在则跳过。
CRUD 操作
Session = sessionmaker(bind=engine)
session = Session()
# 增
new_user = User(name='Alice', age=30)
session.add(new_user)
session.commit()
# 查
user = session.query(User).filter_by(name='Alice').first()
print(user.name, user.age)
users = session.query(User).filter(User.age > 25).all()
for u in users:
print(u.name)
# 改
user.age = 31
session.commit()
# 删
session.delete(user)
session.commit()
session 是数据库会话,相当于一个工作单元。所有改动先缓存在会话里,commit() 时才真正发送到数据库。
Tip查询语句可以链式调用:
session.query(User).filter(User.age > 20).order_by(User.name).limit(10).all()。SQLAlchemy 会把这些调用编译成一条高效的 SQL。
关系映射
SQLAlchemy 也支持外键和关系。一对多关系的示例如下:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String(100))
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', back_populates='addresses')
User.addresses = relationship('Address', back_populates='user')
定义好关系后,可以直接通过对象属性访问关联数据:user.addresses 拿到该用户的所有地址,address.user 拿到所属用户。
何时选 MongoDB,何时选 SQL + ORM
| 维度 | MongoDB | SQL + ORM |
|---|---|---|
| 数据结构 | 灵活,无固定 schema | 严格,需预先定义表结构 |
| 查询方式 | 文档查询,适合嵌套数据 | SQL 查询,适合关联分析 |
| 扩展性 | 水平扩展容易 | 垂直扩展为主 |
| 事务支持 | 4.0+ 支持多文档事务 | 成熟完善 |
| 适用场景 | 日志、内容管理、实时数据 | 电商、金融、复杂报表 |
小结
- PyMongo 的 API 直观,
find_one、insert_many、update_one等方法与 MongoDB 原生命令对应。 - SQLAlchemy 把表变成类、记录变成对象,
session管理事务和生命周期。 - MongoDB 适合 schema 多变、读写频繁的场景;SQLAlchemy 适合关系复杂、事务要求高的业务。
来源:参考了 runoob「Python3 MongoDB」、liaoxuefeng「21.3. 使用SQLAlchemy」等,改写后所得。