项目实战:构建高效可扩展的Flask Web框架:集成Flask-SQLAlchemy、Marshmallow与日志管理
前言
在Web开发中,构建一个既高效又可扩展的框架是项目成功的基石。Flask作为一个轻量级的Web应用框架,凭借其易用性和灵活性,特别适合快速开发和原型设计。结合Flask-SQLAlchemy(为Flask提供SQLAlchemy ORM支持的扩展)和Marshmallow(强大的Python对象序列化/反序列化库),我们能够创建出一个既能高效处理数据库操作又能优雅地转换数据为JSON格式的Web框架。
环境准备
确保MySQL数据库已部署并创建好相应数据库。接着,使用pip安装所需依赖:
pip install Flask Flask-SQLAlchemy marshmallow pymysql
- Flask:用于实现Web应用的接口层。
- Flask-SQLAlchemy:简化在Flask应用中使用SQLAlchemy ORM的操作,处理数据层。
- PyMysql:作为SQLAlchemy的数据库驱动。
- Marshmallow:用于数据的序列化和反序列化,以及数据验证。
App工厂模式
采用app工厂模式来创建Flask应用和数据库连接池,提高代码的可维护性和可测试性。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
# 配置数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://user:password@127.0.0.1:3306/db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 减少开销
# 初始化数据库
db.init_app(app)
with app.app_context():
db.create_all()
return app
日志管理
实现一个日志管理器,用于项目中的日志记录和保存。
import logging
from logging.handlers import RotatingFileHandler
def setup_logging(name, log_level=logging.DEBUG, max_bytes=5*1024*1024, backup_count=5):
"""
配置日志系统。
"""
logger = logging.getLogger(name)
logger.setLevel(log_level)
# 日志文件处理器
file_handler = RotatingFileHandler('app.log', maxBytes=max_bytes, backupCount=backup_count)
file_handler.setLevel(log_level)
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)
# 设置日志格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# 添加处理器到logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
return logger
接口响应统一格式
创建一个工具类来统一接口响应格式。
from flask import jsonify
class Response:
@staticmethod
def success(data=None, msg="成功"):
return jsonify({'data': data, 'msg': msg, 'code': 200})
@staticmethod
def error(msg="错误"):
return jsonify({'msg': msg, 'code': 500})
接口层
定义接口路由和处理函数。
from flask import request
from config.app_factory import create_app, db
from service.project_service import ProjectService
app = create_app()
@app.route('/addProject', methods=['POST'])
def add_project():
project_service = ProjectService()
return project_service.add_project(request.json)
if __name__ == '__main__':
app.run(port=8081)
数据验证与序列化
使用Marshmallow定义数据模型,进行参数验证和序列化。
from marshmallow import Schema, fields, ValidationError
class ProjectSchema(Schema):
id = fields.Int(dump_only=True)
name = fields.Str(required=True, validate=lambda x: len(x) >= 1)
create_time = fields.DateTime(dump_only=True)
update_time = fields.DateTime(dump_only=True)
def __repr__(self):
return f'<User {self.name}>'
服务层
服务层负责业务逻辑处理。
from service.project_service import ProjectService
from config.res_bean import Response
from mapper.project_mapper import ProjectMapper
import config.log as logger
class ProjectService:
def __init__(self):
self.log = logger.setup_logging(self.__class__.__name__)
def add_project(self, json_data):
project_schema = ProjectSchema()
try:
data = project_schema.load(json_data)
return ProjectMapper.add_project(data)
except ValidationError as err:
self.log.error('参数错误:', err)
return Response.error(str(err))
except Exception as e:
self.log.error('添加项目失败:', e)
return Response.error("添加项目失败")
数据模型
定义数据库模型。
from config.app_factory import db
class Project(db.Model):
__tablename__ = 'project'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
create_time = db.Column(db.DateTime, default=db.func.now())
update_time = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())
数据层
实现数据库操作的具体逻辑。
from datetime import datetime
from module.project import Project
from config.res_bean import Response
import config.log as logger
class ProjectMapper:
@staticmethod
def add_project(data):
try:
new_project = Project(name=data['name'], create_time=datetime.now(), update_time=datetime.now())
db.session.add(new_project)
db.session.commit()
logger.setup_logging(ProjectMapper.__name__).info('添加项目成功')
return Response.success(msg="添加项目成功")
except Exception as e:
db.session.rollback()
logger.setup_logging(ProjectMapper.__name__).error('添加项目失败:', e)
return Response.error("添加项目失败")
运行结果
完成以上步骤后,运行应用并调用示例接口进行验证。