flask-前和后打基础,然后看本篇会比较好懂。
一、环境准备与基础配置
1. 导入必要模块
python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
知识延展:
Flask是微框架的核心,所有路由、配置都围绕它展开SQLAlchemy是Python最著名的ORM工具,Flask-SQLAlchemy是其Flask集成版Flask-Migrate基于Alembic,解决数据库结构变更问题(如添加字段)- 密码永远不要明文存储!
werkzeug提供的哈希函数使用PBKDF2算法 datetime.utcnow()获取UTC时间,避免时区问题(生产环境建议用datetime.now(timezone.utc))
2. 创建应用实例
python
app = Flask(__name__)
知识延展:
__name__参数帮助Flask确定模板、静态文件的根目录- 生产环境中通常使用工厂模式(
create_app()函数)替代直接实例化 - 可通过
app.config.from_object()加载配置类,实现环境隔离
二、数据库配置详解
python
# 数据库配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password@localhost:3306/flask_db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'your-secret-key-here'
知识延展:
- 数据库URI支持多种数据库:
sqlite:///app.db,postgresql://...,mongodb://... - 敏感配置应通过环境变量管理:
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') SECRET_KEY生成方法:import secrets; secrets.token_hex(32)- 其他常用配置:
SQLALCHEMY_ECHO=True:打印SQL语句用于调试SQLALCHEMY_POOL_SIZE=10:连接池大小调整
三、初始化扩展组件
python
db = SQLAlchemy(app)
migrate = Migrate(app, db)
知识延展:
- 工厂模式下需延迟初始化:
db = SQLAlchemy()然后在create_app()中db.init_app(app) Migrate对象本身不提供命令,需配合flask-migrate包使用CLI命令- 初始化顺序很重要:必须先有
app和db才能创建migrate
| 代码片段 | db 的作用 |
类比 |
|---|---|---|
class User(db.Model) |
定义蓝图:声明这是一个数据库表模型 | 建筑图纸 |
db.Column(...) |
定义结构:规定列的类型和约束 | 砖块、水泥规格 |
db.session.add() |
准备动作:把数据放入暂存区 | 把家具搬进仓库等待入库 |
db.session.commit() |
执行动作:永久保存数据到硬盘 | 正式办理入库手续 |
User.query... |
读取数据:从数据库查找信息 | 去仓库查询库存 |
db.create_all() |
初始化:根据蓝图建造实际建筑 | 施工队按图纸盖楼 |
四、定义数据模型(ORM核心)
User模型详解
python
class User(db.Model):
__tablename__ = 'users'
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)
password_hash = db.Column(db.String(256), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# 关系
posts = db.relationship('Post', backref='author', lazy=True)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
知识延展:
- 列类型映射:
String→VARCHAR,Text→TEXT,Integer→INT,DateTime→DATETIME - 约束类型:
unique=True,nullable=False,index=True,default=value - 关系加载策略:
lazy='select':单独查询(默认)lazy='joined':JOIN查询lazy='dynamic':返回Query对象用于过滤
- 密码处理最佳实践:
- 永远不要存储明文密码
- 可添加盐值(
generate_password_hash自动处理) - 考虑添加密码强度验证
Post模型详解
python
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 外键关联users表的id字段,建立一对多关系
知识延展:
- 外键约束:
db.ForeignKey('table.column'),删除时可设ondelete='CASCADE' - 复合主键:
primary_key=True可在多个列上设置 - 索引优化:对频繁查询的列添加
index=True - 模型继承:可创建抽象基类共享字段(如
TimestampMixin)
五、数据库初始化命令
python
@app.cli.command('init-db') # 注册自定义CLI命令:flask init-db
def init_db():
db.create_all() # 创建所有未存在的表(不会更新已有表结构)
print('数据库初始化完成!')
知识延展:
db.create_all()仅适用于开发环境,生产环境必须用迁移- 迁移工作流:
flask db init(仅一次)flask db migrate -m "描述"flask db upgrade
- 自定义CLI命令可带参数:
@app.cli.argument('name') - 数据种子:可创建
seed-db命令插入测试数据
六、CRUD操作实战
1. 创建用户(POST)
python
@app.route('/users', methods=['POST'])
def create_user():
data = request.get_json()
user = User(username=data['username'], email=data['email'])
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
return jsonify({'id': user.id}), 201
知识延展:
- 输入验证:应使用
marshmallow或pydantic验证数据 - 错误处理:捕获
IntegrityError处理唯一约束冲突 - 异步支持:Flask 2.0+支持
async def视图函数 - 状态码规范:
- 200:成功
- 201:资源创建成功
- 400:请求错误
- 404:未找到
- 500:服务器错误
2. 查询用户(GET)
python
@app.route('/users/<int:id>')
def get_user(id):
user = User.query.get_or_404(id)
return jsonify({
'id': user.id,
'username': user.username,
'email': user.email
})
知识延展:
- 查询方法:
User.query.get(id):主键查询User.query.filter_by(username='abc'):条件查询User.query.filter(User.age > 18):复杂条件
- 分页查询:
User.query.paginate(page=1, per_page=10) - 序列化优化:使用
Marshmallow定义Schema自动转换
3. 更新用户(PUT)
python
@app.route('/users/<int:id>', methods=['PUT'])
def update_user(id):
user = User.query.get_or_404(id)
data = request.get_json()
# 使用get方法提供默认值,避免KeyError
user.username = data.get('username', user.username)
user.email = data.get('email', user.email)
# 如需更新密码:user.set_password(data['password'])
db.session.commit()
return jsonify({'message': '更新成功'})
知识延展:
- PATCH vs PUT:PATCH部分更新,PUT全量替换
- 乐观锁:添加版本号字段防止并发覆盖
- 审计日志:记录谁在何时修改了什么
- 字段白名单:只允许更新特定字段,防止越权
4. 删除用户(DELETE)
python
@app.route('/users/<int:id>', methods=['DELETE'])
def delete_user(id):
user = User.query.get_or_404(id)
# 注意:如果有外键约束,需先处理关联数据
# 方法1:级联删除(模型中设置cascade='all, delete-orphan')
# 方法2:手动删除关联帖子
# for post in user.posts: db.session.delete(post)
db.session.delete(user)
db.session.commit()
return jsonify({'message': '删除成功'})
知识延展:
- 软删除:添加
deleted_at字段代替物理删除 - 外键策略:
ondelete='CASCADE':自动删除子记录ondelete='SET NULL':子记录外键设为NULL
- 事务管理:使用
with db.session.begin()自动回滚 - 批量操作:
User.query.filter(...).delete()
4. 测试API
bash
# 创建用户
curl -X POST http://localhost:5000/users \
-H "Content-Type: application/json" \
-d '{"username":"alice","email":"alice@example.com","password":"secure123"}'
# 查询用户
curl http://localhost:5000/users/1
-X POST:
-X: 指定 HTTP 请求方法 (Request Method)。
-H: 代表 Header (请求头)。
-d: 代表 Data (数据)。
八、生产环境优化相关
- 配置管理 :使用
.env文件+python-dotenv管理不同环境配置 - 日志系统 :集成
logging模块记录关键操作 - API文档 :使用
Flask-RESTX或Swagger自动生成文档 - 认证授权:添加JWT或OAuth2.0认证机制
- 性能优化 :
- 数据库连接池调优
- 查询结果缓存(Redis)
- 异步任务(Celery)
- 安全防护 :
- SQL注入防护(ORM已内置)
- XSS防护(自动转义)
- 速率限制(
Flask-Limiter)
九、数据库迁移:管理表结构的生命周期
在生产环境中,直接修改数据库表结构是危险的。Flask-Migrate (基于Alembic) 允许我们像管理代码版本一样管理数据库结构。
命令详解与原理
bash
# 初始化迁移
flask db init
# 创建迁移脚本
flask db migrate -m "Initial migration"
# 应用迁移
flask db upgrade
# 回滚迁移
flask db downgrade
知识延展:
- 为什么需要迁移?
db.create_all()只能建表不能改表(如添加字段会报错),而迁移脚本可以安全地执行ALTER TABLE。 - 手动修正 :自动生成的脚本有时不完美(如默认值处理),需人工检查
migrations/versions/*.py文件。 - 多数据库支持:Alembic支持配置多个绑定(binds),可同时迁移MySQL和SQLite。
- 数据迁移:除了结构变更,还可以在迁移脚本中编写Python代码来清洗或转换旧数据。
十、用户认证系统:Flask-Login 深度解析
会话管理是Web应用的核心。Flask-Login 提供了用户会话管理的便捷接口,处理登录、登出、记住我等功能。
1. 初始化与配置
python
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key' # 必须设置,用于加密Cookie会话
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
# 初始化LoginManager
login_manager = LoginManager(app)
login_manager.login_view = 'login' # 未登录用户访问受保护页面时重定向的路由端点
# login_manager.login_message = "请先登录" # 自定义提示消息
知识延展:
- Session机制 :Flask-Login默认使用Cookie存储会话ID,服务器端通过
SECRET_KEY验证签名。 - Remember Me :可通过
login_user(user, remember=True)实现"记住我"功能, Cookie有效期更长。 - 加载器 :
@login_manager.user_loader是必须的,用于根据Session中的ID重新加载用户对象。
2. 用户模型设计
python
# 用户模型必须继承 UserMixin,它提供了 is_authenticated, is_active, is_anonymous, get_id 等属性
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
password_hash = db.Column(db.String(256))
@login_manager.user_loader
def load_user(user_id):
# 根据ID查询用户,返回User对象或None
# 注意:user_id从Session传来是字符串,需转为int
return User.query.get(int(user_id))
知识延展:
- UserMixin的作用 :避免我们手动编写四个标准属性方法。如果需要自定义逻辑(如判断账号是否被冻结),可重写
is_active。 - 匿名用户的处理 :未登录时
current_user是一个AnonymousUserMixin实例,is_authenticated为 False。
3. 注册逻辑(Register)
python
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# 获取表单数据(实际生产中建议使用 Flask-WTF)
username = request.form['username']
password = request.form['password']
# 检查用户名是否存在
if User.query.filter_by(username=username).first():
flash('用户名已存在') # 闪现消息,下次请求时显示并消失
return redirect(url_for('register'))
# 创建新用户
user = User(username=username)
user.password_hash = generate_password_hash(password) # 密码哈希处理
db.session.add(user)
db.session.commit()
flash('注册成功,请登录')
return redirect(url_for('login'))
return render_template('register.html')
知识延展:
- Flash消息 :配合模板中的
get_flashed_messages()使用,适合一次性通知(如"注册成功")。 - 安全性:此处缺少输入验证(长度、特殊字符),生产环境必须加验证逻辑防止XSS或注入。
4. 登录与登出(Login & Logout)
python
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
# 验证用户存在 且 密码哈希匹配
if user and check_password_hash(user.password_hash, password):
login_user(user) # 关键步骤:创建会话
# 可选:处理 next 参数(用户尝试访问受保护页面被重定向来的地址)
# next_page = request.args.get('next')
# return redirect(next_page or url_for('dashboard'))
return redirect(url_for('dashboard'))
flash('用户名或密码错误')
return render_template('login.html')
@app.route('/logout')
@login_required # 装饰器:只有登录用户才能访问此路由
def logout():
logout_user() # 清除会话
return redirect(url_for('index'))
知识延展:
- @login_required :如果未登录,自动重定向到
login_manager.login_view指定的页面,并附带next参数。 - CSRF保护 :原生
request.form没有CSRF保护,建议结合Flask-WTF使用。
5. 受保护的资源
python
@app.route('/dashboard')
@login_required
def dashboard():
# current_user 是全局代理,代表当前登录的用户对象
return f'欢迎,{current_user.username}!'
@app.route('/')
def index():
return render_template('index.html')
十一、RESTful API 开发:令牌认证与资源管理
构建前后端分离应用时,我们需要标准的API接口和无状态的认证机制(如Token)。
1. 基础配置与CORS
python
from flask import Flask, jsonify, request, abort
from flask_httpauth import HTTPTokenAuth
from flask_cors import CORS # 跨域资源共享扩展
app = Flask(__name__)
CORS(app) # 允许所有域名访问API,生产环境应限制特定域名
# CORS(app, resources={r"/api/*": {"origins": "https://myfrontend.com"}})
auth = HTTPTokenAuth(scheme='Bearer') # 定义使用 Bearer Token 方案
知识延展:
- CORS原理 :浏览器出于安全限制不同域名的AJAX请求,服务器需返回
Access-Control-Allow-Origin头。 - 认证方案 :除了Bearer Token,还有Basic Auth (
HTTPTokenAuth(scheme='Basic')),但Token更适合移动端和SPA。
2. Token 验证逻辑
python
# 模拟数据库(实际应查库)
users = {
"user1": "password1",
"user2": "password2"
}
tokens = {} # 内存存储Token,重启后失效,生产环境请用Redis
@auth.verify_token
def verify_token(token):
# Flask-HTTPAuth 调用此函数验证Token有效性
# 如果有效,返回用户标识(如username);无效返回None
if token in tokens:
return tokens[token]
return None
知识延展:
- JWT vs 普通Token :示例使用的是随机UUID存服务器(有状态)。生产环境推荐 JWT (JSON Web Tokens),它将用户信息编码在Token本身,服务器无需存储,实现真正的无状态。
- Token过期:需在Token中加入时间戳,验证时检查是否过期。
3. 获取 Token 接口
python
@app.route('/api/token', methods=['POST'])
def get_token():
auth_data = request.get_json()
username = auth_data.get('username')
password = auth_data.get('password')
# 简单验证
if username in users and users[username] == password:
import uuid
token = str(uuid.uuid4())
tokens[token] = username # 建立映射
return jsonify({'token': token}), 200
abort(401) # 返回 401 Unauthorized
知识延展:
- HTTPS强制:传输密码和Token必须使用HTTPS,否则会被中间人窃听。
- 密码策略:实际项目中密码应对比哈希值,而非明文。
4. RESTful 资源操作 (CRUD)
python
resources = [
{'id': 1, 'name': '资源1', 'description': '描述1'},
{'id': 2, 'name': '资源2', 'description': '描述2'},
]
# GET /api/resources - 获取列表
@app.route('/api/resources', methods=['GET'])
@auth.login_required # 需要Token认证
def get_resources():
return jsonify({'resources': resources})
# GET /api/resources/<id> - 获取单个
@app.route('/api/resources/<int:resource_id>', methods=['GET'])
@auth.login_required
def get_resource(resource_id):
# 使用生成器表达式查找
resource = next((r for r in resources if r['id'] == resource_id), None)
if resource is None:
abort(404) # 资源不存在
return jsonify(resource)
# POST /api/resources - 创建
@app.route('/api/resources', methods=['POST'])
@auth.login_required
def create_resource():
data = request.get_json()
# 简单校验
if 'name' not in data:
abort(400, description="Missing 'name' field")
new_resource = {
'id': len(resources) + 1,
'name': data['name'],
'description': data.get('description', '')
}
resources.append(new_resource)
return jsonify(new_resource), 201 # 201 Created
# PUT /api/resources/<id> - 全量/部分更新
@app.route('/api/resources/<int:resource_id>', methods=['PUT'])
@auth.login_required
def update_resource(resource_id):
resource = next((r for r in resources if r['id'] == resource_id), None)
if resource is None:
abort(404)
data = request.get_json()
resource['name'] = data.get('name', resource['name'])
resource['description'] = data.get('description', resource['description'])
return jsonify(resource)
# DELETE /api/resources/<id> - 删除
@app.route('/api/resources/<int:resource_id>', methods=['DELETE'])
@auth.login_required
def delete_resource(resource_id):
global resources
initial_count = len(resources)
resources = [r for r in resources if r['id'] != resource_id]
if len(resources) == initial_count:
abort(404)
return jsonify({'result': True})
知识延展:
- HTTP动词语义 :
POST: 创建新资源。PUT: 替换整个资源(或部分更新,视API设计而定,严格来说PATCH用于部分更新)。DELETE: 删除资源。
- 状态码规范 :
- 200 OK: 成功。
- 201 Created: 创建成功。
- 204 No Content: 删除成功(通常不返回body)。
- 400 Bad Request: 参数错误。
- 401 Unauthorized: 未认证。
- 403 Forbidden: 已认证但无权限。
- 404 Not Found: 资源不存在。
5. 统一错误处理
python
@app.errorhandler(404)
def not_found(error):
# 统一返回JSON格式错误,而非HTML
return jsonify({'error': 'Not found', 'message': str(error)}), 404
@app.errorhandler(401)
def unauthorized(error):
return jsonify({'error': 'Unauthorized', 'message': 'Invalid token or missing'}), 401
十二、表单处理:Flask-WTF 的安全与验证
手动处理 request.form 既繁琐又不安全。Flask-WTF 集成了 CSRF 保护和强大的数据验证功能。
1. 定义表单类
python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField
# 导入验证器
from wtforms.validators import DataRequired, Email, Length, EqualTo
# 登录表单
class LoginForm(FlaskForm):
# validators 列表按顺序执行,任意一个失败则表单无效
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired(), Length(min=6)])
submit = SubmitField('登录')
# 注册表单
class RegisterForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(min=3, max=20)])
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired(), Length(min=6)])
# EqualTo 确保两次密码输入一致
confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', message='两次密码必须一致')])
submit = SubmitField('注册')
知识延展:
- CSRF Token :
FlaskForm自动生成csrf_token隐藏字段,防止跨站请求伪造攻击。 - 自定义验证器 :可继承
Validator类编写逻辑(如检查用户名是否在黑名单中)。 - 文件上传 :使用
FileField和FileAllowed验证器处理上传。
2. 视图函数集成
python
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
# validate_on_submit() 检查:1. 请求是POST 2. CSRF验证通过 3. 所有字段验证通过
if form.validate_on_submit():
# 访问清洗后的数据
email = form.email.data
# 此处添加实际登录逻辑...
flash(f'登录成功:{email}', 'success')
return redirect(url_for('index'))
# GET请求或验证失败时渲染模板,form中包含错误信息
return render_template('login.html', form=form)
3. 模板渲染 (Jinja2)
html
<form method="POST">
{{ form.hidden_tag() }}
<!-- 自动生成 <input type="hidden" name="csrf_token" ...> -->
<div>
{{ form.email.label }}
{{ form.email() }}
<!-- 遍历错误列表显示 -->
{% for error in form.email.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
<div>
{{ form.password.label }}
{{ form.password() }}
{% for error in form.password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
{{ form.submit() }}
</form>
知识延展:
- Bootstrap集成 :可使用
Flask-Bootstrap或WTForms-Bootstrap自动渲染美观的表单结构。 - 宏(Macros):在Jinja2中定义宏来复用表单字段的渲染逻辑(Label + Input + Error)。
十三、项目结构最佳实践:实际应用
随着代码量增加,将所有代码放在 app.py 会导致难以维护。我们需要采用应用工厂模式 和蓝图(Blueprints)。
1. 推荐的目录结构
text
flask_project/
├── app/
│ ├── __init__.py # 【核心】应用工厂函数 create_app
│ ├── models.py # 数据库模型 (User, Post...)
│ ├── routes/ # 路由模块化
│ │ ├── __init__.py
│ │ ├── main.py # 首页、关于等通用路由
│ │ ├── auth.py # 登录、注册、登出
│ │ └── api.py # REST API 接口
│ ├── templates/ # HTML 模板
│ │ ├── base.html # 基类模板 (包含导航栏、footer)
│ │ ├── auth/ # 认证相关模板
│ │ └── main/ # 主页面模板
│ ├── static/ # 静态资源
│ │ ├── css/
│ │ ├── js/
│ │ └── images/
│ ├── forms.py # WTForms 表单类
│ └── utils.py # 辅助函数 (如发送邮件、格式化时间)
├── migrations/ # 数据库迁移脚本 (由 flask-migrate 生成)
├── tests/ # 单元测试 (pytest/unittest)
├── config.py # 配置类 (Dev, Prod, Test)
├── requirements.txt # 依赖包列表
├── .env # 环境变量 (不要提交到Git!)
├── .gitignore
└── run.py # 入口脚本
知识延展:
- 解耦:路由、模型、表单分离,便于多人协作和单元测试。
- 蓝图(Blueprint) :
auth_bp,api_bp允许我们在不同模块定义路由,最后统一注册到主应用。
2. 应用工厂模式 (app/__init__.py)
这是现代Flask项目的核心,解决了循环导入问题,并支持多实例测试。
python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
from config import Config # 导入配置类
# 初始化扩展实例(此时未绑定app)
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()
def create_app(config_class=Config):
app = Flask(__name__)
# 加载配置
app.config.from_object(config_class)
# 初始化扩展并绑定app
db.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
# 配置 LoginManager
login_manager.login_view = 'auth.login' # 指向 auth 蓝图的路由
# 注册蓝图
# 导入必须在函数内部,避免循环导入
from app.routes.main import main_bp
from app.routes.auth import auth_bp
from app.routes.api import api_bp
app.register_blueprint(main_bp) # 根路径
app.register_blueprint(auth_bp, url_prefix='/auth') # /auth/login, /auth/register
app.register_blueprint(api_bp, url_prefix='/api') # /api/resources
return app
知识延展:
- 循环导入问题 :如果在文件顶部
from app import app,而app又导入routes,routes又导入app,就会报错。工厂模式将app的创建推迟到函数内部,解决了这个问题。 - 测试友好 :可以在测试代码中调用
create_app(TestConfig)创建独立的测试实例,不影响开发环境。
3. 配置文件管理 (config.py)
使用类继承和环境变量管理不同环境的配置。
python
import os
from datetime import timedelta
class Config:
# 密钥优先从环境变量读取,防止硬编码泄露
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key-fallback'
# 数据库URL
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 会话永久有效期
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
class DevelopmentConfig(Config):
DEBUG = True
# 开发环境可开启 SQL 打印
# SQLALCHEMY_ECHO = True
class ProductionConfig(Config):
DEBUG = False
# 生产环境应使用强随机密钥和正式数据库
pass
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' # 测试用内存数据库
# 配置字典,方便通过字符串选择
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'testing': TestingConfig,
'default': DevelopmentConfig
}
启动脚本 (run.py):
python
import os
from app import create_app, db
from app.models import User # 导入模型以便 shell 中使用
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
if __name__ == '__main__':
app.run()
Tips:完整实例之后会单独发表在资源栏目,敬请期待(*❦ω❦)
