Flask入门教程(十三):数据库操作——SQLAlchemy与CRUD完整实践

1. 使用Flask-SQLAlchemy

SQLAlchemy是一个强大的ORM(对象关系映射)库,通过Python对象与数据库表进行交互,无需编写SQL语句。Flask-SQLAlchemy是Flask的官方扩展,集成了SQLAlchemy。

安装Flask-SQLAlchemy

复制代码
pip install flask-sqlalchemy

配置SQLAlchemy

复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# SQLite数据库(开发环境推荐)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

2. 定义模型

模型是数据库表的Python类,每个模型类代表数据库中的一张表。

复制代码
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    age = db.Column(db.Integer, nullable=True)

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

常用字段类型

字段类型 说明 Python类型
db.Integer 整数 int
db.String(n) 可变长度字符串 str
db.Text 长文本 str
db.Boolean 布尔值 bool
db.DateTime 日期时间 datetime.datetime
db.Date 日期 datetime.date
db.Float 浮点数 float
db.Decimal 高精度小数 decimal.Decimal
db.JSON JSON数据 dict / list

常用字段参数

参数 说明
primary_key=True 主键
unique=True 值唯一
nullable=False 不允许为空
default=value 默认值
index=True 创建索引
autoincrement=True 自增(整数主键默认)

3. 创建和管理数据库

在定义了模型后,需要在应用上下文中创建数据库和表:

复制代码
with app.app_context():
    db.create_all()  # 创建所有模型对应的表

删除所有表(谨慎使用)

复制代码
with app.app_context():
    db.drop_all()  # 删除所有表,数据会丢失

4. CRUD操作

创建记录(Create)

复制代码
@app.route('/add_user')
def add_user():
    new_user = User(username='john_doe', email='john@example.com', age=25)
    db.session.add(new_user)   # 添加到会话
    db.session.commit()        # 提交事务,保存到数据库
    return 'User added!'

# 批量添加
@app.route('/add_users')
def add_users():
    users = [
        User(username='alice', email='alice@example.com'),
        User(username='bob', email='bob@example.com'),
    ]
    db.session.add_all(users)
    db.session.commit()
    return 'Users added!'

读取记录(Read)

复制代码
# 查询所有记录
@app.route('/get_users')
def get_users():
    users = User.query.all()
    return '<br>'.join([f'{user.username} ({user.email})' for user in users])

# 通过主键查询单个记录
user = User.query.get(1)  # 查询id=1的用户

# 通过条件查询(精确匹配)
user = User.query.filter_by(username='john_doe').first()

# 通过条件查询(多个条件)
users = User.query.filter_by(username='john_doe', age=25).all()

# 获取第一条记录
user = User.query.first()

更新记录(Update)

复制代码
@app.route('/update_user/<int:user_id>')
def update_user(user_id):
    user = User.query.get(user_id)
    if user:
        user.username = 'new_username'
        user.age = 26
        db.session.commit()
        return 'User updated!'
    return 'User not found!'

删除记录(Delete)

复制代码
@app.route('/delete_user/<int:user_id>')
def delete_user(user_id):
    user = User.query.get(user_id)
    if user:
        db.session.delete(user)
        db.session.commit()
        return 'User deleted!'
    return 'User not found!'

5. 高级查询操作

条件查询

复制代码
from sqlalchemy import or_, and_, not_

# AND条件(默认)
users = User.query.filter(User.username == 'john_doe', User.age > 18).all()

# OR条件
users = User.query.filter(
    or_(User.username == 'john_doe', User.email == 'john@example.com')
).all()

# AND显式
users = User.query.filter(
    and_(User.age >= 18, User.age <= 60)
).all()

# NOT条件
users = User.query.filter(not_(User.username == 'admin')).all()

# 模糊查询(LIKE)
users = User.query.filter(User.username.like('%john%')).all()

# 包含查询(IN)
users = User.query.filter(User.username.in_(['alice', 'bob'])).all()

# 为空判断
users = User.query.filter(User.email.is_(None)).all()

排序与分页

复制代码
# 升序
users = User.query.order_by(User.username).all()

# 降序
users = User.query.order_by(User.username.desc()).all()

# 多字段排序
users = User.query.order_by(User.age.desc(), User.username).all()

# 分页查询(每页10条,第1页)
page = User.query.paginate(page=1, per_page=10)
users = page.items          # 当前页的数据
total = page.total          # 总记录数
pages = page.pages          # 总页数
has_prev = page.has_prev    # 是否有上一页
has_next = page.has_next    # 是否有下一页

聚合查询

复制代码
from sqlalchemy import func

# 计数
count = User.query.count()

# 求和
total_age = db.session.query(func.sum(User.age)).scalar()

# 平均值
avg_age = db.session.query(func.avg(User.age)).scalar()

# 最大值/最小值
max_age = db.session.query(func.max(User.age)).scalar()
min_age = db.session.query(func.min(User.age)).scalar()

6. 使用Flask-Migrate进行数据库迁移

当模型发生变化时(如新增字段),Flask-Migrate可以生成迁移脚本,自动更新表结构而不丢失数据。

安装Flask-Migrate

复制代码
pip install flask-migrate

配置Flask-Migrate

复制代码
from flask_migrate import Migrate

migrate = Migrate(app, db)

迁移命令

复制代码
# 1. 初始化迁移环境(只需执行一次)
flask db init

# 2. 生成迁移脚本(检测模型变化)
flask db migrate -m "添加age字段"

# 3. 应用迁移到数据库
flask db upgrade

# 4. 回滚到上一个版本
flask db downgrade
命令 作用
flask db init 初始化迁移环境,生成migrations/目录
flask db migrate -m "描述" 生成迁移脚本(不修改数据库)
flask db upgrade 应用迁移,更新数据库结构
flask db downgrade 回滚到上一个迁移版本

7. 执行原始SQL

虽然SQLAlchemy提供了强大的ORM功能,但在某些复杂场景下可能需要执行原始SQL语句。

复制代码
# 查询
@app.route('/raw_sql')
def raw_sql():
    result = db.session.execute('SELECT * FROM user')
    return '<br>'.join([str(row) for row in result])

# 带参数的查询(防止SQL注入)
@app.route('/user/<int:user_id>')
def get_user_raw(user_id):
    result = db.session.execute(
        'SELECT * FROM user WHERE id = :id',
        {'id': user_id}
    )
    user = result.fetchone()
    return f'User: {user.username}' if user else 'Not found'

8. 连接MySQL数据库

除了SQLite,Flask-SQLAlchemy也支持MySQL、PostgreSQL等主流数据库。

安装MySQL驱动

复制代码
# 选择一种安装
pip install mysqlclient    # 推荐,性能好
# 或
pip install pymysql        # 纯Python实现

配置MySQL连接

复制代码
# URI格式: mysql://用户名:密码@主机:端口/数据库名
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost:3306/dbname'
# 如需指定字符集
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/dbname?charset=utf8mb4'

完整示例

复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@localhost/mydb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

@app.route('/')
def index():
    users = User.query.all()
    return '<br>'.join([f'{user.username} ({user.email})' for user in users])

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

9. 常用数据库URI格式

数据库 URI格式
SQLite sqlite:///path/to/database.db
SQLite(内存) sqlite:///:memory:
MySQL mysql://username:password@host/dbname
PostgreSQL postgresql://username:password@host/dbname
MariaDB mariadb://username:password@host/dbname

10. CRUD操作速查表

操作 代码
创建记录 db.session.add(obj); db.session.commit()
批量创建 db.session.add_all([obj1, obj2]); db.session.commit()
查询所有 Model.query.all()
主键查询 Model.query.get(id)
条件查询(单条) Model.query.filter_by(key=value).first()
条件查询(多条) Model.query.filter_by(key=value).all()
复杂条件 Model.query.filter(or_(...)).all()
排序 Model.query.order_by(Model.field.desc()).all()
分页 Model.query.paginate(page=1, per_page=10)
更新 obj.field = new_value; db.session.commit()
删除 db.session.delete(obj); db.session.commit()
计数 Model.query.count()

小结

本章全面讲解了Flask的数据库操作。Flask-SQLAlchemy是推荐的ORM方案------通过定义继承自db.Model的模型类来映射数据库表,使用db.Column定义字段;CRUD操作通过db.session.add()创建、Model.query查询、直接修改属性后commit()更新、db.session.delete()删除;高级查询支持filter/filter_by条件过滤、or_/and_组合条件、order_by排序、paginate分页;Flask-Migrate管理数据库迁移;也支持执行原始SQL和连接MySQL等主流数据库。这些知识构成了Flask数据持久化的完整基础。

相关推荐
两点王爷13 小时前
PostgreSQL 常用 SQL 语句与 GIS 相关函数详解
数据库·后端
两点王爷13 小时前
PostgreSQL 好用又独特的特性与空间函数
数据库
梦帮科技13 小时前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
TDengine (老段)15 小时前
TDengine 常见问题 TOP3
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
troy12816 小时前
Python 基础语法(九):Django/Flask/FastAPI 三大 Web 框架详细对比解析
python·jupyter·django·flask·github·fastapi
Lucifer三思而后行16 小时前
Oracle SQL 优化实战:明明走了索引,SQL 还是慢?
sql·oracle
螺蛳粉 螺蛳粉17 小时前
MySQL 分布式集群系列 · 第五篇——全方位对比:NDB、MGR、主从复制、分库分表怎么选?
数据库·分布式·mysql
这个DBA有点耶21 小时前
从OLTP到OLAP到HTAP:数据库负载分类的技术演进与选型指南
数据库·mysql·架构
YangYang9YangYan1 天前
商业数据分析校招项目怎么选,附项目设计与简历包装思路
大数据·数据库·数据分析
李白客1 天前
数据库培训怎么选?零基础到DBA的学习路线与机构认证对比(2026)
数据库·学习