Flask-SQLAlchemy全面指南:从模型定义到高级查询

一、初识Flask-SQLAlchemy

1.1 为什么选择ORM?

传统SQL操作存在以下痛点:
• SQL注入风险
• 不同数据库语法差异
• 重复编写CRUD代码
• 对象与关系数据转换繁琐

Flask-SQLAlchemy优势:

# 传统SQL操作
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# ORM方式
user = User.query.get(user_id)

1.2 安装与配置

安装命令:

pip install flask-sqlalchemy pymysql

基础配置示例:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://user:password@localhost/dbname'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

配置参数说明:
SQLALCHEMY_POOL_SIZE: 连接池默认大小(推荐5-10)
SQLALCHEMY_ECHO: 开启SQL日志(调试模式)
SQLALCHEMY_ENGINE_OPTIONS: 高级引擎配置

二、数据模型定义

2.1 学生模型示例

class Student(db.Model):
    """学生信息表"""
    __tablename__ = 'tb_student'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), nullable=False)
    sex = db.Column(db.Boolean, default=True, comment='性别')
    age = db.Column(db.SmallInteger, index=True)
    class_name = db.Column('class', db.String(10))
    description = db.Column(db.Text)
    status = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.now)

    def __repr__(self):
        return f'<Student {self.name}>'

字段类型对照表:

ORM类型 MySQL类型 说明
Integer INT 32位整数
String(20) VARCHAR(20) 可变长度字符串
Text TEXT 长文本数据
Boolean TINYINT(1) 布尔值存储
DateTime DATETIME 日期时间类型

三、CRUD操作详解

3.1 创建数据

# 单条创建
new_student = Student(name='王小明', class_name='301', age=16)
db.session.add(new_student)
db.session.commit()

# 批量创建
students = [
    Student(name='张小红', class_name='302', age=17),
    Student(name='李小白', class_name='303', age=16)
]
db.session.bulk_save_objects(students)
db.session.commit()

3.2 查询操作

基础查询方法:

# 获取全部数据
all_students = Student.query.all()

# 获取第一条记录
first_student = Student.query.first()

# 主键查询
student = Student.query.get(1)

复杂条件查询:

from sqlalchemy import and_, or_

# 组合查询示例
result = Student.query.filter(
    or_(
        and_(Student.class_name == '301', Student.age >= 15),
        and_(Student.class_name == '302', Student.age < 18)
    )
).order_by(Student.created_at.desc()).limit(10).all()

3.3 更新数据

student = Student.query.get(1)
student.age = 17
db.session.commit()

# 批量更新
Student.query.filter_by(class_name='301').update({'age': Student.age + 1})
db.session.commit()

3.4 删除数据

student = Student.query.get(1)
db.session.delete(student)
db.session.commit()

四、高级查询技巧

4.1 分页查询

def paginate(page=1, per_page=20):
    return Student.query.order_by(Student.id).paginate(
        page=page, 
        per_page=per_page,
        error_out=False
    )

4.2 聚合查询

from sqlalchemy import func

# 统计班级人数
class_stats = db.session.query(
    Student.class_name,
    func.count(Student.id).label('total')
).group_by(Student.class_name).all()

4.3 关联查询

class Score(db.Model):
    student_id = db.Column(db.Integer, db.ForeignKey('tb_student.id'))
    # 定义关系
    student = db.relationship('Student', backref='scores')

# 关联查询示例
student_with_scores = db.session.query(Student, Score).join(
    Score, Student.id == Score.student_id
).filter(Student.class_name == '301').all()

五、原生SQL操作

5.1 执行原生查询

# 参数化查询防止SQL注入
sql = "SELECT * FROM tb_student WHERE class = :class_name"
result = db.session.execute(sql, {'class_name': '301'})
students = [dict(row) for row in result]

5.2 执行数据修改

update_sql = """
    UPDATE tb_student 
    SET age = age + 1 
    WHERE created_at < :threshold
"""
db.session.execute(update_sql, {'threshold': datetime(2023, 1, 1)})
db.session.commit()

六、最佳实践

6.1 性能优化

• 使用yield_per处理大数据集:

for student in Student.query.yield_per(100):
    process(student)

• 避免N+1查询问题:

# 使用joinedload进行关联加载
from sqlalchemy.orm import joinedload
students = Student.query.options(joinedload(Student.scores)).all()

6.2 安全建议

  1. 始终使用参数化查询
  2. 敏感字段加密存储
  3. 定期备份数据库
  4. 使用只读账号进行查询操作

6.3 错误处理

try:
    db.session.begin()
    # 数据库操作...
    db.session.commit()
except Exception as e:
    db.session.rollback()
    current_app.logger.error(f"Database error: {str(e)}")
    raise

七、扩展学习

  1. 数据库迁移工具

    pip install flask-migrate
    

    初始化:

    from flask_migrate import Migrate
    migrate = Migrate(app, db)
    
  2. 查询性能分析

    from sqlalchemy import event
    from sqlalchemy.engine import Engine
    
    @event.listens_for(Engine, "before_cursor_execute")
    def before_cursor_execute(conn, cursor, stmt, params, context, executemany):
        context._query_start_time = time.time()
    
    @event.listens_for(Engine, "after_cursor_execute")
    def after_cursor_execute(conn, cursor, stmt, params, context, executemany):
        duration = time.time() - context._query_start_time
        if duration > 0.5:  # 记录慢查询
            app.logger.warning(f"Slow query ({duration:.2f}s): {stmt}")
    
  3. 异步支持(SQLAlchemy 2.0+):

    from sqlalchemy.ext.asyncio import create_async_engine
    async_engine = create_async_engine("mysql+asyncmy://user:pass@host/db")
    

通过本文的学习,您将掌握:
• Flask-SQLAlchemy的核心使用方法
• 复杂业务场景下的查询构建技巧
• 数据库操作的最佳实践
• 性能优化与安全防护策略

建议在实际项目中结合具体需求,灵活运用这些技术,并持续关注SQLAlchemy的版本更新和新特性。

posted @ 2025-03-26 15:27  千陌666  阅读(243)  评论(0)    收藏  举报