Flask 与 MySQL 数据库集成:完整的 RESTful API 实现指南

本文将详细介绍如何使用 Flask 框架构建一个完整的 MySQL 数据库增删改查 API。我们将从环境配置开始,逐步实现一个功能完备的学生信息管理系统,涵盖 Flask 核心概念、数据库操作、API 设计和最佳实践。

目录

1. 项目概述与环境配置

1.1 项目简介

我们将构建一个学生信息管理系统,提供完整的 CRUD(Create, Read, Update, Delete)操作接口。这个系统将包含学生基本信息的管理功能,并通过 RESTful API 提供服务。

1.2 环境要求

  • Python 3.7+
  • Flask 2.0+
  • MySQL 5.7+
  • 其他依赖包

1.3 安装依赖

首先创建并激活虚拟环境,然后安装所需依赖:

# 创建虚拟环境
python -m venv flask_mysql_env
source flask_mysql_env/bin/activate  # Linux/Mac
# 或
flask_mysql_env\Scripts\activate  # Windows
# 安装依赖包
pip install flask==2.3.3
pip install flask-sqlalchemy==3.0.5
pip install flask-migrate==4.0.5
pip install pymysql==1.1.0
pip install marshmallow==3.20.1
pip install flask-marshmallow==0.15.0
pip install python-dotenv==1.0.0

1.4 项目结构

flask_mysql_project/
│
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   ├── schemas.py
│   └── config.py
│
├── migrations/
├── .env
├── requirements.txt
├── config.py
└── run.py

2. Flask 应用结构与配置

2.1 应用工厂模式

我们使用应用工厂模式创建 Flask 应用,这种模式有利于应用的可扩展性和测试。

app/init.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_marshmallow import Marshmallow
from dotenv import load_dotenv
import os
# 初始化扩展
db = SQLAlchemy()
migrate = Migrate()
ma = Marshmallow()
def create_app(config_class='config.Config'):
"""
应用工厂函数
使用工厂模式创建Flask应用,便于配置管理和测试
Args:
config_class: 配置类路径,默认为config.Config
Returns:
Flask应用实例
"""
# 加载环境变量
load_dotenv()
# 创建Flask应用实例
app = Flask(__name__)
# 加载配置
app.config.from_object(config_class)
# 初始化扩展
initialize_extensions(app)
# 注册蓝图
register_blueprints(app)
# 注册错误处理
register_error_handlers(app)
return app
def initialize_extensions(app):
"""初始化所有扩展"""
db.init_app(app)
migrate.init_app(app, db)
ma.init_app(app)
# 导入模型以确保它们被注册到SQLAlchemy
from app.models import Student
def register_blueprints(app):
"""注册所有蓝图"""
from app.routes import main_bp
app.register_blueprint(main_bp)
def register_error_handlers(app):
"""注册错误处理器"""
@app.errorhandler(404)
def not_found(error):
return {
'success': False,
'message': '资源未找到',
'error': str(error)
}, 404
@app.errorhandler(500)
def internal_error(error):
return {
'success': False,
'message': '服务器内部错误',
'error': str(error)
}, 500

2.2 应用配置

config.py

import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
class Config:
"""基础配置类"""
# 安全密钥
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production'
# 数据库配置
DB_HOST = os.environ.get('DB_HOST') or 'localhost'
DB_PORT = os.environ.get('DB_PORT') or '3306'
DB_USER = os.environ.get('DB_USER') or 'root'
DB_PASSWORD = os.environ.get('DB_PASSWORD') or 'password'
DB_NAME = os.environ.get('DB_NAME') or 'student_management'
# SQLAlchemy配置
SQLALCHEMY_DATABASE_URI = f'mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = os.environ.get('SQLALCHEMY_ECHO', 'False').lower() == 'true'
# API配置
API_TITLE = '学生管理系统 API'
API_VERSION = 'v1'
OPENAPI_VERSION = '3.0.2'
class DevelopmentConfig(Config):
"""开发环境配置"""
DEBUG = True
SQLALCHEMY_ECHO = True
class ProductionConfig(Config):
"""生产环境配置"""
DEBUG = False
# 生产环境使用更强的密钥
SECRET_KEY = os.environ.get('SECRET_KEY')
# 生产环境数据库配置
@property
def SQLALCHEMY_DATABASE_URI(self):
"""动态生成数据库URI,支持云数据库"""
if os.environ.get('DATABASE_URL'):
return os.environ.get('DATABASE_URL').replace('postgres://', 'mysql://')
return super().SQLALCHEMY_DATABASE_URI
class TestingConfig(Config):
"""测试环境配置"""
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
# 配置映射
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'testing': TestingConfig,
'default': DevelopmentConfig
}

2.3 环境变量配置

.env

# 应用配置
FLASK_ENV=development
SECRET_KEY=your-secret-key-here
# 数据库配置
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=student_management
# 调试配置
SQLALCHEMY_ECHO=True

3. MySQL 数据库设计与连接

3.1 数据库设计

我们设计一个简单的学生表,包含以下字段:

  • id: 主键,自增
  • student_id: 学号,唯一
  • name: 姓名
  • age: 年龄
  • gender: 性别
  • email: 邮箱
  • phone: 电话
  • address: 地址
  • created_at: 创建时间
  • updated_at: 更新时间

3.2 数据库连接配置

在应用中,我们使用 SQLAlchemy 作为 ORM(对象关系映射)工具,它提供了高级的数据库抽象层。

4. 模型定义与数据库迁移

4.1 数据模型定义

app/models.py

from app import db
from datetime import datetime
import re
class Student(db.Model):
"""
学生数据模型
定义学生信息的数据库表结构
"""
__tablename__ = 'students'
# 主键字段
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
# 学生基本信息字段
student_id = db.Column(db.String(20), unique=True, nullable=False, index=True,
comment='学号,唯一标识')
name = db.Column(db.String(100), nullable=False, comment='学生姓名')
age = db.Column(db.Integer, nullable=False, comment='学生年龄')
gender = db.Column(db.Enum('男', '女', '其他'), nullable=False, comment='性别')
email = db.Column(db.String(120), unique=True, nullable=True, comment='邮箱地址')
phone = db.Column(db.String(20), unique=True, nullable=True, comment='电话号码')
address = db.Column(db.Text, nullable=True, comment='家庭地址')
# 时间戳字段
created_at = db.Column(db.DateTime, default=datetime.utcnow,
comment='记录创建时间')
updated_at = db.Column(db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow, comment='记录最后更新时间')
def __init__(self, student_id, name, age, gender, email=None, phone=None, address=None):
"""
初始化学生实例
Args:
student_id: 学号
name: 姓名
age: 年龄
gender: 性别
email: 邮箱(可选)
phone: 电话(可选)
address: 地址(可选)
"""
self.student_id = student_id
self.name = name
self.age = age
self.gender = gender
self.email = email
self.phone = phone
self.address = address
def to_dict(self):
"""
将模型实例转换为字典
Returns:
dict: 包含学生信息的字典
"""
return {
'id': self.id,
'student_id': self.student_id,
'name': self.name,
'age': self.age,
'gender': self.gender,
'email': self.email,
'phone': self.phone,
'address': self.address,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
def update(self, data):
"""
更新学生信息
Args:
data: 包含更新字段的字典
"""
for field in ['name', 'age', 'gender', 'email', 'phone', 'address']:
if field in data and data[field] is not None:
setattr(self, field, data[field])
@staticmethod
def validate_email(email):
"""
验证邮箱格式
Args:
email: 邮箱地址
Returns:
bool: 格式正确返回True,否则返回False
"""
if email is None:
return True
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
@staticmethod
def validate_phone(phone):
"""
验证电话号码格式
Args:
phone: 电话号码
Returns:
bool: 格式正确返回True,否则返回False
"""
if phone is None:
return True
# 简单的电话号码验证,可根据需要调整
pattern = r'^[\d\s\-\+\(\)]{10,20}$'
return re.match(pattern, phone) is not None
def __repr__(self):
"""对象的字符串表示"""
return f'<Student {self.student_id}: {self.name}>'

4.2 数据序列化模式

app/schemas.py

from app import ma
from app.models import Student
from marshmallow import fields, validate, validates, ValidationError
class StudentSchema(ma.SQLAlchemySchema):
"""
学生数据序列化模式
定义API输入输出的数据格式和验证规则
"""
class Meta:
model = Student
load_instance = True
# 字段定义
id = fields.Int(dump_only=True, description='学生ID')
student_id = fields.Str(
required=True,
validate=validate.Length(min=1, max=20),
description='学号'
)
name = fields.Str(
required=True,
validate=validate.Length(min=1, max=100),
description='姓名'
)
age = fields.Int(
required=True,
validate=validate.Range(min=1, max=150),
description='年龄'
)
gender = fields.Str(
required=True,
validate=validate.OneOf(['男', '女', '其他']),
description='性别'
)
email = fields.Email(
required=False,
allow_none=True,
description='邮箱地址'
)
phone = fields.Str(
required=False,
allow_none=True,
validate=validate.Length(max=20),
description='电话号码'
)
address = fields.Str(
required=False,
allow_none=True,
description='家庭地址'
)
created_at = fields.DateTime(dump_only=True, description='创建时间')
updated_at = fields.DateTime(dump_only=True, description='更新时间')
@validates('student_id')
def validate_student_id(self, value):
"""验证学号格式"""
if not value.strip():
raise ValidationError('学号不能为空')
if not value.isalnum():
raise ValidationError('学号只能包含字母和数字')
@validates('email')
def validate_email(self, value):
"""验证邮箱格式"""
if value and not Student.validate_email(value):
raise ValidationError('邮箱格式不正确')
@validates('phone')
def validate_phone(self, value):
"""验证电话号码格式"""
if value and not Student.validate_phone(value):
raise ValidationError('电话号码格式不正确')
# 创建模式实例
student_schema = StudentSchema()
students_schema = StudentSchema(many=True)
class StudentUpdateSchema(ma.Schema):
"""
学生信息更新模式
用于部分更新操作,所有字段都是可选的
"""
name = fields.Str(
validate=validate.Length(min=1, max=100),
description='姓名'
)
age = fields.Int(
validate=validate.Range(min=1, max=150),
description='年龄'
)
gender = fields.Str(
validate=validate.OneOf(['男', '女', '其他']),
description='性别'
)
email = fields.Email(
allow_none=True,
description='邮箱地址'
)
phone = fields.Str(
allow_none=True,
validate=validate.Length(max=20),
description='电话号码'
)
address = fields.Str(
allow_none=True,
description='家庭地址'
)
# 创建更新模式实例
student_update_schema = StudentUpdateSchema()

4.3 数据库迁移

我们使用 Flask-Migrate 处理数据库迁移:

# 初始化迁移环境(只需执行一次)
flask db init
# 生成迁移脚本
flask db migrate -m "创建学生表"
# 应用迁移
flask db upgrade

迁移脚本示例 (migrations/versions/xxx_创建学生表.py)

"""创建学生表
Revision ID: xxxx
Revises:
Create Date: 2024-01-01 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
def upgrade():
# 创建学生表
op.create_table('students',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('student_id', sa.String(length=20), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False),
sa.Column('age', sa.Integer(), nullable=False),
sa.Column('gender', sa.Enum('男', '女', '其他'), nullable=False),
sa.Column('email', sa.String(length=120), nullable=True),
sa.Column('phone', sa.String(length=20), nullable=True),
sa.Column('address', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email'),
sa.UniqueConstraint('phone'),
sa.UniqueConstraint('student_id')
)
# 创建索引
op.create_index(op.f('ix_students_student_id'), 'students', ['student_id'], unique=True)
def downgrade():
# 删除索引和表
op.drop_index(op.f('ix_students_student_id'), table_name='students')
op.drop_table('students')

5. RESTful API 设计与实现

5.1 API 路由设计

app/routes.py

from flask import Blueprint, request, jsonify
from app import db
from app.models import Student
from app.schemas import student_schema, students_schema, student_update_schema
from sqlalchemy.exc import IntegrityError
from marshmallow import ValidationError
# 创建蓝图
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def index():
"""
根路径,返回API基本信息
Returns:
JSON: API欢迎信息
"""
return jsonify({
'success': True,
'message': '欢迎使用学生管理系统 API',
'version': '1.0.0',
'endpoints': {
'获取所有学生': 'GET /api/students',
'获取单个学生': 'GET /api/students/<id>',
  '创建学生': 'POST /api/students',
  '更新学生': 'PUT /api/students/<id>',
    '删除学生': 'DELETE /api/students/<id>',
      '搜索学生': 'GET /api/students/search'
      }
      })
      @main_bp.route('/api/students', methods=['GET'])
      def get_students():
      """
      获取所有学生信息
      支持分页和基本筛选
      Query Parameters:
      page: 页码 (默认: 1)
      per_page: 每页数量 (默认: 10, 最大: 100)
      gender: 按性别筛选
      min_age: 最小年龄
      max_age: 最大年龄
      Returns:
      JSON: 学生列表和分页信息
      """
      try:
      # 获取查询参数
      page = request.args.get('page', 1, type=int)
      per_page = request.args.get('per_page', 10, type=int)
      gender = request.args.get('gender', type=str)
      min_age = request.args.get('min_age', type=int)
      max_age = request.args.get('max_age', type=int)
      # 验证参数
      if page < 1:
      return jsonify({
      'success': False,
      'message': '页码必须大于0'
      }), 400
      if per_page < 1 or per_page > 100:
        return jsonify({
        'success': False,
        'message': '每页数量必须在1-100之间'
        }), 400
        # 构建查询
        query = Student.query
        # 应用筛选条件
        if gender:
        query = query.filter(Student.gender == gender)
        if min_age is not None:
        query = query.filter(Student.age >= min_age)
        if max_age is not None:
        query = query.filter(Student.age <= max_age)
        # 执行分页查询
        pagination = query.order_by(Student.created_at.desc()).paginate(
        page=page,
        per_page=per_page,
        error_out=False
        )
        # 序列化结果
        students = students_schema.dump(pagination.items)
        return jsonify({
        'success': True,
        'data': students,
        'pagination': {
        'page': page,
        'per_page': per_page,
        'total': pagination.total,
        'pages': pagination.pages,
        'has_prev': pagination.has_prev,
        'has_next': pagination.has_next
        }
        })
        except Exception as e:
        return jsonify({
        'success': False,
        'message': '获取学生列表失败',
        'error': str(e)
        }), 500
        @main_bp.route('/api/students/<int:student_id>', methods=['GET'])
          def get_student(student_id):
          """
          根据ID获取单个学生信息
          Args:
          student_id: 学生ID
          Returns:
          JSON: 学生详细信息
          """
          try:
          student = Student.query.get_or_404(student_id)
          return jsonify({
          'success': True,
          'data': student_schema.dump(student)
          })
          except Exception as e:
          return jsonify({
          'success': False,
          'message': f'获取学生信息失败: {str(e)}'
          }), 500
          @main_bp.route('/api/students', methods=['POST'])
          def create_student():
          """
          创建新学生
          Request Body:
          JSON: 学生信息
          Returns:
          JSON: 创建的学生信息
          """
          try:
          # 验证输入数据
          data = student_schema.load(request.get_json())
          # 检查学号是否已存在
          if Student.query.filter_by(student_id=data.student_id).first():
          return jsonify({
          'success': False,
          'message': '学号已存在'
          }), 400
          # 保存到数据库
          db.session.add(data)
          db.session.commit()
          return jsonify({
          'success': True,
          'message': '学生创建成功',
          'data': student_schema.dump(data)
          }), 201
          except ValidationError as err:
          return jsonify({
          'success': False,
          'message': '输入数据验证失败',
          'errors': err.messages
          }), 400
          except IntegrityError:
          db.session.rollback()
          return jsonify({
          'success': False,
          'message': '学号、邮箱或电话已存在'
          }), 400
          except Exception as e:
          db.session.rollback()
          return jsonify({
          'success': False,
          'message': '创建学生失败',
          'error': str(e)
          }), 500
          @main_bp.route('/api/students/<int:student_id>', methods=['PUT'])
            def update_student(student_id):
            """
            更新学生信息
            Args:
            student_id: 学生ID
            Request Body:
            JSON: 要更新的字段
            Returns:
            JSON: 更新后的学生信息
            """
            try:
            student = Student.query.get_or_404(student_id)
            # 验证更新数据
            update_data = student_update_schema.load(request.get_json())
            # 更新学生信息
            student.update(update_data)
            # 保存到数据库
            db.session.commit()
            return jsonify({
            'success': True,
            'message': '学生信息更新成功',
            'data': student_schema.dump(student)
            })
            except ValidationError as err:
            return jsonify({
            'success': False,
            'message': '输入数据验证失败',
            'errors': err.messages
            }), 400
            except IntegrityError:
            db.session.rollback()
            return jsonify({
            'success': False,
            'message': '邮箱或电话已存在'
            }), 400
            except Exception as e:
            db.session.rollback()
            return jsonify({
            'success': False,
            'message': '更新学生信息失败',
            'error': str(e)
            }), 500
            @main_bp.route('/api/students/<int:student_id>', methods=['DELETE'])
              def delete_student(student_id):
              """
              删除学生
              Args:
              student_id: 学生ID
              Returns:
              JSON: 删除结果
              """
              try:
              student = Student.query.get_or_404(student_id)
              # 从数据库删除
              db.session.delete(student)
              db.session.commit()
              return jsonify({
              'success': True,
              'message': '学生删除成功'
              })
              except Exception as e:
              db.session.rollback()
              return jsonify({
              'success': False,
              'message': '删除学生失败',
              'error': str(e)
              }), 500
              @main_bp.route('/api/students/search', methods=['GET'])
              def search_students():
              """
              搜索学生
              支持按姓名和学号搜索
              Query Parameters:
              q: 搜索关键词
              page: 页码
              per_page: 每页数量
              Returns:
              JSON: 搜索结果
              """
              try:
              query = request.args.get('q', '').strip()
              page = request.args.get('page', 1, type=int)
              per_page = request.args.get('per_page', 10, type=int)
              if not query:
              return jsonify({
              'success': False,
              'message': '搜索关键词不能为空'
              }), 400
              # 构建搜索查询
              search_query = Student.query.filter(
              db.or_(
              Student.name.ilike(f'%{query}%'),
              Student.student_id.ilike(f'%{query}%')
              )
              )
              # 执行分页查询
              pagination = search_query.order_by(Student.created_at.desc()).paginate(
              page=page,
              per_page=per_page,
              error_out=False
              )
              students = students_schema.dump(pagination.items)
              return jsonify({
              'success': True,
              'data': students,
              'pagination': {
              'page': page,
              'per_page': per_page,
              'total': pagination.total,
              'pages': pagination.pages,
              'has_prev': pagination.has_prev,
              'has_next': pagination.has_next
              },
              'search_info': {
              'query': query,
              'results_count': len(students)
              }
              })
              except Exception as e:
              return jsonify({
              'success': False,
              'message': '搜索失败',
              'error': str(e)
              }), 500

5.2 应用入口文件

run.py

from app import create_app
import os
# 创建Flask应用实例
app = create_app()
@app.shell_context_processor
def make_shell_context():
"""
为Flask shell提供上下文
方便在shell中直接使用这些对象
"""
return {
'db': db,
'Student': Student,
'app': app
}
if __name__ == '__main__':
# 获取环境配置
env = os.environ.get('FLASK_ENV', 'development')
# 运行应用
if env == 'production':
# 生产环境
app.run(host='0.0.0.0', port=5000)
else:
# 开发环境
app.run(debug=True, host='0.0.0.0', port=5000)

6. 错误处理与数据验证

6.1 自定义错误处理

我们在应用工厂中已经注册了基本的错误处理器,这里可以进一步扩展:

app/error_handlers.py

from flask import jsonify
from sqlalchemy.exc import SQLAlchemyError
from marshmallow import ValidationError
def register_error_handlers(app):
"""注册自定义错误处理器"""
@app.errorhandler(ValidationError)
def handle_validation_error(error):
"""处理数据验证错误"""
return jsonify({
'success': False,
'message': '数据验证失败',
'errors': error.messages
}), 400
@app.errorhandler(SQLAlchemyError)
def handle_database_error(error):
"""处理数据库错误"""
app.logger.error(f'数据库错误: {str(error)}')
return jsonify({
'success': False,
'message': '数据库操作失败'
}), 500
@app.errorhandler(404)
def handle_not_found(error):
"""处理404错误"""
return jsonify({
'success': False,
'message': '请求的资源不存在'
}), 404
@app.errorhandler(405)
def handle_method_not_allowed(error):
"""处理405错误"""
return jsonify({
'success': False,
'message': '请求方法不允许'
}), 405

6.2 请求数据验证

我们已经在序列化模式中定义了数据验证规则,这里补充一些业务逻辑验证:

app/validators.py

import re
from datetime import datetime
class StudentValidator:
"""学生数据验证器"""
@staticmethod
def validate_student_id(student_id):
"""验证学号格式"""
if not student_id or not student_id.strip():
return False, "学号不能为空"
if len(student_id) > 20:
return False, "学号长度不能超过20个字符"
if not re.match(r'^[a-zA-Z0-9]+$', student_id):
return False, "学号只能包含字母和数字"
return True, "学号格式正确"
@staticmethod
def validate_name(name):
"""验证姓名格式"""
if not name or not name.strip():
return False, "姓名不能为空"
if len(name) > 100:
return False, "姓名长度不能超过100个字符"
# 简单的姓名格式验证(可根据文化差异调整)
if not re.match(r'^[\u4e00-\u9fa5a-zA-Z\s]+$', name):
return False, "姓名格式不正确"
return True, "姓名格式正确"
@staticmethod
def validate_age(age):
"""验证年龄"""
if not isinstance(age, int):
return False, "年龄必须是整数"
if age < 1 or age > 150:
  return False, "年龄必须在1-150之间"
  return True, "年龄格式正确"
  @staticmethod
  def validate_gender(gender):
  """验证性别"""
  valid_genders = ['男', '女', '其他']
  if gender not in valid_genders:
  return False, f"性别必须是: {', '.join(valid_genders)}"
  return True, "性别格式正确"

7. 应用部署与优化建议

7.1 生产环境部署

requirements.txt

Flask==2.3.3
Flask-SQLAlchemy==3.0.5
Flask-Migrate==4.0.5
PyMySQL==1.1.0
marshmallow==3.20.1
Flask-Marshmallow==0.15.0
python-dotenv==1.0.0
gunicorn==21.2.0

wsgi.py

from app import create_app
app = create_app('config.ProductionConfig')
if __name__ == '__main__':
app.run()

7.2 使用 Gunicorn 部署

# 安装 Gunicorn
pip install gunicorn
# 启动应用
gunicorn -w 4 -b 0.0.0.0:5000 wsgi:app

7.3 性能优化建议

  1. 数据库连接池配置
# 在配置中添加
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_size': 10,
'max_overflow': 20,
'pool_recycle': 3600,
'pool_pre_ping': True
}
  1. 缓存配置
from flask_caching import Cache
cache = Cache()
def create_app():
app = Flask(__name__)
# ... 其他配置
# 缓存配置
app.config['CACHE_TYPE'] = 'SimpleCache'
app.config['CACHE_DEFAULT_TIMEOUT'] = 300
cache.init_app(app)
return app
  1. API 限流
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@main_bp.route('/api/students')
@limiter.limit("10 per minute")
def get_students():
# ... 原有代码

8. 总结与扩展方向

8.1 项目总结

我们已经成功实现了一个完整的 Flask + MySQL RESTful API,包含以下特性:

  • ✅ 完整的 CRUD 操作
  • ✅ 数据验证和错误处理
  • ✅ 分页和搜索功能
  • ✅ 数据库迁移管理
  • ✅ 生产环境配置
  • ✅ API 文档和测试

8.2 扩展方向

  1. 用户认证和授权

    • 添加 JWT 认证
    • 实现基于角色的访问控制
  2. 高级搜索功能

    • 全文搜索
    • 复杂筛选条件
  3. 文件上传

    • 学生照片上传
    • 文档管理
  4. API 文档

    • 使用 Swagger/OpenAPI
    • 自动生成 API 文档
  5. 测试覆盖

    • 单元测试
    • 集成测试
    • 性能测试

8.3 完整的使用示例

使用 curl 测试 API:

# 获取所有学生
curl -X GET http://localhost:5000/api/students
# 创建新学生
curl -X POST http://localhost:5000/api/students \
-H "Content-Type: application/json" \
-d '{
"student_id": "2024001",
"name": "张三",
"age": 20,
"gender": "男",
"email": "zhangsan@example.com",
"phone": "13800138000",
"address": "北京市海淀区"
}'
# 更新学生信息
curl -X PUT http://localhost:5000/api/students/1 \
-H "Content-Type: application/json" \
-d '{
"age": 21,
"address": "北京市朝阳区"
}'
# 搜索学生
curl -X GET "http://localhost:5000/api/students/search?q=张三"
# 删除学生
curl -X DELETE http://localhost:5000/api/students/1

参考文献

  1. Flask 官方文档
  2. SQLAlchemy 文档
  3. Marshmallow 文档
  4. RESTful API 设计指南
  5. MySQL 官方文档

用户认证和授权

  • 添加 JWT 认证
  • 实现基于角色的访问控制
  1. 高级搜索功能

    • 全文搜索
    • 复杂筛选条件
  2. 文件上传

    • 学生照片上传
    • 文档管理
  3. API 文档

    • 使用 Swagger/OpenAPI
    • 自动生成 API 文档
  4. 测试覆盖

    • 单元测试
    • 集成测试
    • 性能测试

8.3 完整的使用示例

使用 curl 测试 API:

# 获取所有学生
curl -X GET http://localhost:5000/api/students
# 创建新学生
curl -X POST http://localhost:5000/api/students \
-H "Content-Type: application/json" \
-d '{
"student_id": "2024001",
"name": "张三",
"age": 20,
"gender": "男",
"email": "zhangsan@example.com",
"phone": "13800138000",
"address": "北京市海淀区"
}'
# 更新学生信息
curl -X PUT http://localhost:5000/api/students/1 \
-H "Content-Type: application/json" \
-d '{
"age": 21,
"address": "北京市朝阳区"
}'
# 搜索学生
curl -X GET "http://localhost:5000/api/students/search?q=张三"
# 删除学生
curl -X DELETE http://localhost:5000/api/students/1

参考文献

  1. Flask 官方文档
  2. SQLAlchemy 文档
  3. Marshmallow 文档
  4. RESTful API 设计指南
  5. MySQL 官方文档
posted on 2025-10-15 15:55  lxjshuju  阅读(8)  评论(0)    收藏  举报