63·模块十三:Web开发基础高级

Flask 与数据库集成(SQLAlchemy)

flaskdatabasessqlalchemyorm

第63课 - Flask 与数据库集成(SQLAlchemy)

学习目标

  1. 理解 ORM(对象关系映射)的基本概念及其在 Web 开发中的优势。
  2. 掌握在 Flask 应用中配置和初始化 SQLAlchemy 的方法。
  3. 学会使用 SQLAlchemy 定义数据模型(表结构)。
  4. 熟练运用 SQLAlchemy 进行基本的数据库增删改查(CRUD)操作。
  5. 能够将数据库操作集成到 Flask 路由中,构建动态数据驱动的 Web 应用。

核心概念

1. 什么是 ORM?

想象一下,你正在用 Python 写代码,而数据库只懂 SQL 语言。你需要一个"翻译官"来帮你把 Python 的"命令"(对象、属性、方法)翻译成数据库能听懂的 SQL 语句,并把数据库返回的结果再翻译回 Python 对象。这个"翻译官"就是 ORM (Object-Relational Mapping,对象关系映射)

使用 ORM 的好处是:

  • 更 Pythonic:用操作对象的方式操作数据库,代码更易读、易写。
  • 数据库无关性:理论上,更换数据库(如从 SQLite 换到 PostgreSQL)只需修改配置,而无需重写所有数据库查询代码。
  • 提高开发效率:避免了手动编写和拼接复杂的 SQL 语句。

2. SQLAlchemy 与 Flask-SQLAlchemy

SQLAlchemy 是 Python 生态中最强大、最流行的 ORM 工具之一。Flask-SQLAlchemy 则是它的一个轻量级扩展,专门为 Flask 应用做了适配,简化了集成和配置过程。

3. 核心组件

  • 应用 (App) 和配置 (Config):Flask 应用实例,包含数据库连接字符串(SQLALCHEMY_DATABASE_URI)等配置。
  • 引擎 (Engine):SQLAlchemy 核心,负责管理数据库连接池和实际通信。
  • 会话 (Session):所有数据库操作的"沙箱"。我们通过会话来添加、修改、删除对象,并最终通过 commit() 提交事务使更改生效。
  • 模型 (Model):一个普通的 Python 类,继承自 db.Model。这个类映射到数据库中的一张表。类属性定义了表的列。

代码示例

以下是一个完整的示例,演示如何用 Flask 和 SQLAlchemy 创建一个简单的"用户管理"应用。

步骤 1:安装依赖

pip install flask flask-sqlalchemy

步骤 2:创建应用 (app.py)

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy

# 1. 初始化 Flask 应用
app = Flask(__name__)

# 2. 配置数据库 (这里使用SQLite,文件会自动创建)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'your-secret-key' # 用于闪存消息

# 3. 初始化数据库实例
db = SQLAlchemy(app)

# 4. 定义数据模型 (User表)
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) # 邮箱,唯一,非空

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

# 5. 在第一次请求前创建数据库表
@app.before_request
def create_tables():
    db.create_all()

# 6. 路由:首页,显示所有用户
@app.route('/')
def index():
    users = User.query.all() # 查询所有用户
    return render_template('index.html', users=users)

# 7. 路由:添加用户
@app.route('/add', methods=['POST'])
def add_user():
    username = request.form.get('username')
    email = request.form.get('email')
    if username and email:
        new_user = User(username=username, email=email)
        db.session.add(new_user)
        db.session.commit()
        flash('用户添加成功!', 'success')
    else:
        flash('用户名和邮箱不能为空!', 'danger')
    return redirect(url_for('index'))

# 8. 路由:删除用户
@app.route('/delete/<int:user_id>')
def delete_user(user_id):
    user_to_delete = User.query.get_or_404(user_id) # 根据ID查询,不存在则返回404
    db.session.delete(user_to_delete)
    db.session.commit()
    flash('用户已删除!', 'success')
    return redirect(url_for('index'))

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

步骤 3:创建模板 (templates/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户管理</title>
</head>
<body>
    <h1>用户列表</h1>
    {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
            {% for category, message in messages %}
                <p class="{{ category }}">{{ message }}</p>
            {% endfor %}
        {% endif %}
    {% endwith %}

    <form method="POST" action="{{ url_for('add_user') }}">
        <input type="text" name="username" placeholder="用户名" required>
        <input type="email" name="email" placeholder="邮箱" required>
        <button type="submit">添加</button>
    </form>

    <ul>
        {% for user in users %}
            <li>
                {{ user.username }} ({{ user.email }})
                <a href="{{ url_for('delete_user', user_id=user.id) }}">删除</a>
            </li>
        {% else %}
            <li>暂无用户。</li>
        {% endfor %}
    </ul>
</body>
</html>

运行与演示:

  1. 运行 python app.py
  2. 访问 http://127.0.0.1:5000/,你将看到一个简单的用户管理界面。
  3. 尝试添加和删除用户。数据将被持久化存储在当前目录下的 instance/site.db 文件中。

实践练习

练习 1:基础扩展

在现有代码的基础上,为 User 模型添加一个 age (整数) 字段。修改 add_user 路由和模板以支持年龄输入,并确保在显示用户列表时也能看到年龄。

练习 2:实现编辑功能

创建一个新的路由 /edit/<int:user_id>,该路由:

  1. 对于 GET 请求,显示一个预填充了用户当前信息的表单。
  2. 对于 POST 请求,接收表单数据并更新数据库中的对应用户。 在 index.html 的每个用户条目旁添加一个"编辑"链接。

练习 3:引入关系查询(进阶)

创建一个新的模型 Post,表示用户发布的文章。Post 模型应包含 id, title, content, user_id (外键) 等字段。在 User 模型中添加与 Post 的一对多关系。修改用户详情页面,使其能显示该用户发布的所有文章标题。

常见错误

  1. 忘记在应用上下文中运行代码

    • 错误:在应用初始化完成前(或在独立的 Python 脚本中)直接运行 db.create_all()
    • 解决:使用 app.before_request 钩子或在 if __name__ == '__main__': 块内,先 with app.app_context(): db.create_all()
  2. 模型定义后未重新创建表

    • 错误:修改了模型(如添加新字段),但数据库中已存在的表结构没有更新,导致 OperationalError
    • 解决:在开发阶段,最简单的办法是删除旧的数据库文件(如 site.db),然后重启应用让 db.create_all() 重新创建。生产环境应使用 数据库迁移工具(如 Flask-Migrate)。
  3. 混淆 query.get()query.filter()

    • 错误:使用 User.query.get(username) 试图按用户名查询(get 只适用于主键查询)。
    • 解决:按非主键字段查询应使用 User.query.filter_by(username=username).first()
  4. 忘记提交会话

    • 错误:调用了 db.session.add()db.session.delete(),但没有调用 db.session.commit()
    • 结果:对数据库的更改不会生效,内存中的对象状态已变,但数据库无变化。

小结

本课我们学习了如何将强大的 SQLAlchemy ORM 集成到 Flask 应用中。核心要点包括:

  • ORM 是连接 Python 对象和关系数据库的桥梁,让数据操作更直观。
  • Flask-SQLAlchemy 提供了便捷的接口来配置数据库和定义模型。
  • 数据模型 通过继承 db.Model 类并定义类属性来映射到数据库表。
  • 数据库操作 通过 db.session 对象进行,遵循 添加/修改/删除 -> 提交 的事务模式。
  • CRUD 操作 可以轻松地与 Flask 路由结合,构建完整的数据驱动应用。

掌握了 Flask 与 SQLAlchemy 的集成,你就拥有了构建大多数 Web 应用所需的核心数据持久化能力。下一课,我们将学习如何使用 Flask 构建 REST API,将这些数据以标准化的方式提供给前端或第三方客户端。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「使用 Flask 构建 REST API」 以巩固所学知识。