【Flask】Explore-Flask:早期 Flask 生态的实用指南
开源项目:explore-flask/README.rst at master · rpicard/explore-flask (github.com)
一、Coding conventions
Summary
-
Try to follow the coding style conventions laid out in PEP 8.
-
Try to document your app with docstrings as defined in PEP 257.
def launch_rocket():"""Main launch sequence director.Locks seatbelts, initiates radio and fires engines."""# [...]
-
Use relative imports to import your app’s internal modules.
# myapp/views.py# An absolute import gives us the User model
from myapp.models import User# A relative import does the same thing
from .models import User
✅ 至今仍然适用的原则
1. 遵循 PEP 8 代码风格
-
为什么有效:
PEP 8 仍是 Python 官方推荐的代码风格标准,确保代码一致性和可读性。-
例如:缩进用 4 空格、变量名用
snake_case
、类名用CamelCase
。
-
-
现代工具支持:
-
自动格式化工具(如
black
、autopep8
)可强制遵循 PEP 8。 -
IDE(如 VS Code、PyCharm)内置 PEP 8 检查。
-
-
注意:
PEP 8 是指南而非铁律,部分规则可灵活调整(如行长度默认 88/79 字符,但black
强制 88)。
2. 使用 PEP 257 文档字符串(Docstrings)
-
为什么有效:
-
文档字符串是 Python 生态的通用约定,IDE 和工具(如 Sphinx、pydoc)依赖它生成文档。
-
类型注解(Type Hints)的普及(PEP 484)并未取代文档字符串,而是互补。
-
-
推荐格式:
-
Google 风格(简洁)或 NumPy 风格(详细),而非严格的 PEP 257 原始格式。
-
def calculate(a: int, b: int) -> int:"""Compute the sum of two integers.Args:a: First integer.b: Second integer.Returns:Sum of a and b."""return a + b
3. 相对导入(Relative Imports)的合理使用
-
适用场景:
-
在 包内部模块互相引用 时,相对导入(
from . import module
)仍是最清晰的方式。 -
避免硬编码包名,提高可移植性(如重构时包名变更不影响导入)。
-
-
现代补充:
-
结合
__init__.py
和pyproject.toml
定义包结构(PEP 621)。
-
⚠️ 需要调整或谨慎使用的原则
1. 相对导入的潜在问题
-
问题场景:
-
在脚本直接运行(
python script.py
)时,相对导入可能失败(因__package__
未定义)。 -
复杂的项目结构(如嵌套包)可能导致导入混乱。
-
-
现代建议:
-
优先使用 绝对导入(
from mypackage import module
)除非明确需要相对导入。 -
将可执行脚本放在包外,或通过
python -m mypackage.module
运行。
-
2. PEP 8 的局部调整
-
灵活性增强:
-
行长度:
black
等工具默认允许 88 字符(原 PEP 8 建议 79)。 -
类型注解:PEP 8 已更新允许更灵活的类型注解换行(PEP 484+)。
-
-
例外情况:
-
某些 API 设计(如 Django 的
models.ForeignKey
)可能不符合 PEP 8 命名,但遵循框架惯例更重要。
-
3. 文档字符串的过度工程化
-
旧问题:
PEP 257 的原始规范(如单行文档字符串的格式)可能过于严格。 -
现代实践:
-
更注重 实用性(如 Google/NumPy 风格),而非机械遵循 PEP 257。
-
工具(如
pydocstyle
)可配置检查规则。
-
🔧 2023 年推荐的最佳实践
原则 | 现代调整建议 |
---|---|
PEP 8 风格 | 用 black 自动格式化,局部例外可通过 # fmt: off 忽略。 |
文档字符串 | 结合类型注解 + Google/NumPy 风格,用 mkdocs 或 Sphinx 生成文档。 |
相对导入 | 仅在包内部使用;脚本和顶层模块用绝对导入。 |
总结:如何应用这些原则 today?
-
坚持核心规范:
-
PEP 8 和文档字符串仍是 Python 开发的基石,但可通过工具自动化。
-
-
灵活调整细节:
-
行长度、导入方式等根据项目和团队需求调整。
-
-
结合现代工具链:
-
格式化:
black
+isort
。 -
文档:
mkdocs-material
+pydocstyle
。 -
导入:优先绝对导入,包内用相对导入。
-
这些原则的核心理念(可读性、一致性、可维护性)始终重要,但实现方式更智能高效了。
二、Environment
Summary
-
Use virtualenv to keep your application’s dependencies together.
-
Use virtualenvwrapper to keep your virtual environments together.
-
Keep track of dependencies with one or more text files.
-
Use a version control system. I recommend Git.
-
Use .gitignore to keep clutter and secrets out of version control.
-
Debug mode can give you information about problems in development.
-
The Flask-DebugToolbar extension will give you even more of that information.
✅ 至今仍然适用的原则
1. 使用虚拟环境隔离依赖(virtualenv)
-
为什么有效:
Python 项目依赖冲突问题依然存在(尤其是不同项目需要同一库的不同版本时)。虚拟环境仍是官方推荐的依赖隔离方案。 -
现代改进:
Python 3.3+ 内置了venv
模块(python -m venv venv
),但virtualenv
仍更灵活(如支持旧版 Python)。
2. 使用版本控制系统(Git)
-
为什么有效:
Git 已成为行业标准(尤其是配合 GitHub/GitLab),代码版本管理、协作、回滚等需求不变。 -
现代补充:
可结合pre-commit
等工具自动化代码检查。
3. 用 .gitignore
排除无关文件
-
为什么有效:
避免提交编译文件(如.pyc
)、敏感信息(如.env
)、IDE 配置等仍是基本规范。 -
现代扩展:
现在更推荐使用 环境变量(如python-dotenv
)或 专用配置管理工具(如 Vault)管理密钥,而非手动忽略文件。
4. 记录依赖清单(requirements.txt)
-
为什么有效:
明确依赖是项目可复现的基础。 -
现代改进:
-
推荐使用
pip-tools
或poetry
管理依赖(自动处理子依赖版本冲突)。 -
区分开发/生产依赖(如
requirements-dev.txt
)。
-
5. 调试模式与工具(Flask-DebugToolbar)
-
为什么有效:
Debug 模式和 DebugToolbar 仍是快速定位问题的有效工具。 -
注意点:
需确保仅限开发环境使用(生产环境禁用!)。
⚠️ 需要调整或过时的原则
1. virtualenvwrapper 的必要性降低
-
原因:
-
现代工具(如
poetry
、pipenv
)已内置虚拟环境管理功能。 -
IDE(如 VS Code、PyCharm)直接支持虚拟环境切换,减少手动操作需求。
-
-
建议:
新项目可优先尝试poetry
(依赖管理 + 虚拟环境一体化)。
2. 纯手动维护依赖文件(pip freeze)
-
问题:
pip freeze
会导出所有依赖(包括间接依赖),导致文件臃肿且难以维护。 -
替代方案:
-
使用
poetry
的pyproject.toml
或pipenv
的Pipfile
显式声明依赖。 -
仅锁定版本时生成
requirements.txt
(如部署用)。
-
3. Flask-DebugToolbar 的局限性
-
现代挑战:
-
对异步框架(如 FastAPI)支持有限。
-
前端复杂应用可能需要更专业的调试工具(如浏览器 DevTools + 后端日志聚合)。
-
-
替代方案:
结合logging
、Sentry
(错误追踪)、Postman
(API 调试)等。
🔧 2023 年推荐的工具链升级
传统方式 | 现代替代方案 | 优势 |
---|---|---|
virtualenv + pip | poetry / pdm | 依赖解析、虚拟环境管理一体化 |
requirements.txt | pyproject.toml (PEP 621) | 标准化依赖声明,支持元数据 |
Flask-DebugToolbar | pdbpp + logging + Sentry | 更灵活的调试和错误监控 |
总结:如何应用这些原则 today?
-
仍要坚持:
-
隔离环境、版本控制、依赖记录、调试安全。
-
-
需要更新:
-
用
poetry
替代virtualenvwrapper
+ 手动pip
。 -
敏感信息改用环境变量或专用服务管理。
-
-
扩展实践:
-
容器化(Docker)进一步隔离环境。
-
CI/CD 自动化测试和部署。
-
这些原则的核心思想(隔离性、可复现性、安全性)依然重要,只是工具更高效了。
三、Organizing your project
Summary
-
Using a single module for your application is good for quick projects.
-
Using a package for your application is good for projects with views, models, forms and other components.
config.py
requirements.txt
run.py
instance/config.py
yourapp/__init__.pyviews.pymodels.pyforms.pystatic/templates/
-
Blueprints are a great way to organize projects with several distinct components.
✅ 至今仍然适用的原则
1. 单模块适合小型项目
-
适用场景:
-
快速原型、微服务或简单 API(如一个
app.py
包含路由和逻辑)。 -
仍常见于教程、实验性代码或小型工具开发。
-
-
现代补充:
-
即使单文件,也应遵循模块化设计(如分离路由、业务逻辑)。
-
可搭配
Flask 2.0
的async
支持提升简单应用的性能。
-
2. 包结构适合复杂项目
-
为什么有效:
-
分层架构(如
models/
,views/
,services/
)仍是中大型项目的标准实践。 -
支持更好的可测试性和可维护性。
-
-
现代改进:
-
结合
工厂模式
(Factory Pattern)创建应用实例(通过create_app()
函数)。 -
使用
Flask-SQLAlchemy
或Flask-Pydantic
等扩展规范组件交互。
-
3. 蓝图(Blueprints)组织多组件
-
核心优势:
-
模块化路由:将不同功能(如用户认证、API 版本)拆分为独立蓝图。
-
资源隔离:每个蓝图可拥有自己的模板、静态文件。
-
-
现代实践:
-
在微服务架构中,蓝图仍用于单体应用内的功能分区。
-
结合
Flask-RESTX
或Flask-Smorest
构建结构化 API。
-
⚠️ 需要调整或谨慎使用的原则
1. 单模块的局限性
-
问题场景:
-
随着项目增长,单文件难以维护(路由、模型、逻辑混杂)。
-
缺乏明确的依赖管理,易导致代码臃肿。
-
-
替代方案:
-
即使小型项目,也建议拆分为
app.py
+extensions.py
+config.py
等。
-
2. 纯包结构的冗余性
-
旧问题:
传统包结构(如myapp/__init__.py
+myapp/views.py
)可能导致过度分层。 -
现代优化:
-
按功能垂直拆分(如
auth/
,blog/
子包),而非按技术分层(models/
,views/
)。 -
使用
Dependency Injection
替代隐式导入(减少循环依赖)。
-
3. 蓝图的替代方案
-
新兴趋势:
-
FastAPI 的 APIRouter:类似蓝图但更轻量,适合纯 API 项目。
-
微服务拆分:若组件独立性极强,可直接拆分为独立服务(而非蓝图)。
-
-
注意:
蓝图仍适用于 Flask 单体应用,但需避免过度设计(如嵌套蓝图)。
🔧 2023 年推荐的项目组织方式
中型项目(包 + 蓝图)
myapp/
├── __init__.py # create_app() 工厂函数
├── auth/ # 认证蓝图
│ ├── routes.py
│ └── models.py
├── blog/ # 博客蓝图
│ ├── routes.py
│ └── templates/
├── extensions.py # 数据库、缓存等扩展
└── config.py
大型项目(按功能垂直拆分)
myapp/
├── core/ # 核心逻辑
├── api/ # API 蓝图(可进一步拆分为 v1/, v2/)
├── cli/ # 命令行工具
├── tests/ # 按功能匹配的测试结构
└── config/├── dev.py└── prod.py
总结:如何应用这些原则 today?
-
坚持核心思想:
-
简单项目用单文件,复杂项目用包+蓝图。
-
模块化设计始终重要。
-
-
现代调整:
-
优先按功能(而非技术)划分代码。
-
结合工厂模式和依赖注入提升灵活性。
-
-
评估替代方案:
-
纯 API 项目可考虑 FastAPI;
-
超大型应用直接拆微服务。
-
Flask 的这些原则仍具指导意义,但需根据项目规模和团队需求灵活调整。
四、configuration
Summary
-
A simple app may only need one configuration file: config.py.
DEBUG = True # Turns on debugging features in Flask
BCRYPT_LOG_ROUNDS = 12 # Configuration for the Flask-Bcrypt extension
MAIL_FROM_EMAIL = "robert@example.com" # For use in application emails
# app.py or app/__init__.py
from flask import Flaskapp = Flask(__name__)
app.config.from_object('config')# Now we can access the configuration variables via app.config["VAR_NAME"].
-
Instance folders can help us hide secret configuration values.
config.py
requirements.txt
run.py
instance/config.py
yourapp/__init__.pymodels.pyviews.pytemplates/static/
# app.py or app/__init__.pyapp = Flask(__name__, instance_relative_config=True)
app.config.from_object('config')
app.config.from_pyfile('config.py')
-
Instance folders can be used to alter an application’s configuration for a specific environment.
-
We should use environment variables and
app.config.from_envvar()
for more complicated environment-based configurations.
1. 简单应用只需一个 config.py
✅ 仍有优势,但需谨慎使用
-
适用场景:
-
快速原型开发、小型项目、个人工具。
-
无需多环境部署或敏感信息的场景。
-
-
优势:
-
简单直接,适合低复杂度项目。
-
-
过时点:
-
硬编码敏感信息:现代开发中,直接写密码/API 密钥到文件是严重的安全反模式。
-
环境适应性差:无法轻松切换开发/生产配置。
-
改进建议:
即使小型项目,也应避免硬编码敏感信息,至少用.env
文件 +python-dotenv
。
2. 使用 Instance Folders 隐藏敏感配置
⚠️ 部分过时,仍有特定用途
-
适用场景:
-
传统 Flask 项目(非云原生部署)。
-
需要本地开发与生产配置分离的简单场景。
-
-
优势:
-
避免敏感配置提交到版本控制(如
instance/config.py
在.gitignore
中)。
-
-
过时点:
-
云原生兼容性差:现代部署(Docker/K8s)更依赖环境变量或 Secrets 管理。
-
不够动态:需手动维护不同环境的实例文件夹,不符合自动化流程。
-
改进建议:
云原生项目中,优先使用环境变量或 Secrets 管理工具(如 Vault、K8s Secrets)。
3. 使用环境变量 + app.config.from_envvar()
✅ 仍是黄金标准
-
适用场景:
-
任何需要多环境(开发/测试/生产)支持的项目。
-
云原生、容器化(Docker/K8s)或 Serverless 部署。
-
-
优势:
-
安全性:敏感信息通过运行时注入,不暴露在代码中。
-
灵活性:无需修改代码即可切换环境配置。
-
符合 12-Factor App:被现代 DevOps 工具链(CI/CD)原生支持。
-
-
注意事项:
-
需配合工具(如
python-dotenv
)简化本地开发。
-
现代扩展:
使用更高级的配置库(如dynaconf
、pydantic-settings
)支持多格式(YAML/JSON)和类型校验。
4. 混合配置策略的演进
✅ 推荐实践:分层配置
现代项目通常结合以下方式:
-
默认配置:
config.py
或settings.toml
(非敏感值)。 -
环境覆盖:通过环境变量或
.env
文件(开发环境)。 -
生产机密:通过云平台 Secrets 管理(如 AWS Secrets Manager)。
优势:
兼顾开发便利性与生产安全性。
避免“过时”方案的硬编码问题。
总结:哪些原则已过时?
原则 | 是否过时 | 原因 | 替代方案 |
---|---|---|---|
单一 config.py | 部分过时 | 硬编码不安全 | 默认配置 + 环境变量覆盖 |
Instance Folders | 基本过时 | 云原生兼容性差 | 环境变量/Secrets |
环境变量 | 仍是主流 | 符合现代实践 | 无,可扩展工具链 |
现代最佳实践建议:
-
简单项目:
.env
+python-dotenv
+config.py
(仅非敏感配置)。 -
复杂项目:环境变量 +
dynaconf
/pydantic-settings
+ 云 Secrets 管理。 -
彻底弃用:硬编码敏感信息、依赖实例文件夹切换环境。
云原生时代,环境变量和集中式 Secrets 管理已成为事实标准,而传统方法仅适用于遗留项目或极简场景。
五、Advanced patterns for views and routing
Summary
-
The
@login_required
decorator from Flask-Login helps you limit views to authenticated users.
# app.pyfrom flask import render_template
from flask_login import login_required, current_user@app.route('/')
def index():return render_template("index.html")@app.route('/dashboard')
@login_required
def account():return render_template("account.html")
-
The Flask-Cache extension gives you a bunch of decorators to implement various methods of caching.
# app.pyfrom flask_cache import Cache
from flask import Flaskapp = Flask()# We'd normally include configuration settings in this call
cache = Cache(app)@app.route('/')
@cache.cached(timeout=60)
def index():[...] # Make a few database calls to get the information we needreturn render_template('index.html',latest_posts=latest_posts,recent_users=recent_users,recent_photos=recent_photos)
-
We can develop custom view decorators to help us organize our code and stick to DRY (Don’t Repeat Yourself) coding principles.
# myapp/util.pyfrom functools import wraps
from datetime import datetimefrom flask import flash, redirect, url_forfrom flask_login import current_userdef check_expired(func):@wraps(func)def decorated_function(*args, **kwargs):if datetime.utcnow() > current_user.account_expires:flash("Your account has expired. Update your billing info.")return redirect(url_for('account_billing'))return func(*args, **kwargs)return decorated_function
-
Custom URL converters can be a great way to implement creative features involving URL’s.
1. @login_required
装饰器(Flask-Login)
✅ 仍在广泛使用
-
现状:
-
Flask-Login
仍是 Flask 生态中最主流的身份验证库,@login_required
是限制未登录访问的标准方式。 -
配合现代前端(如 JWT、OAuth2)时,可能改用权限校验中间件(如
Flask-JWT-Extended
),但传统 Session 登录场景仍依赖此装饰器。
-
-
优势:
-
简单直观,适合服务端渲染(SSR)或混合应用。
-
-
注意点:
-
若项目完全基于 API(如 React/Vue 前端),可能改用 JWT 的
@jwt_required
(但逻辑类似)。
-
2. Flask-Cache 的缓存装饰器
⚠️ 已过时,被替代
-
现状:
-
Flask-Cache
官方已停止维护,其继任者是Flask-Caching
(支持更现代的缓存后端,如 Redis、Memcached)。 -
装饰器(如
@cache.cached()
)仍在使用,但底层实现更高效。
-
-
现代替代方案:
-
使用
Flask-Caching
+ Redis 实现分布式缓存。 -
对于 API 项目,可能直接用 CDN 缓存 或 HTTP 缓存头(如
Cache-Control
)。
-
关键变化:
缓存逻辑从“代码装饰器”扩展到“基础设施层”(如 Redis、Nginx)。
3. 自定义视图装饰器(DRY 原则)
✅ 仍是核心实践
-
现状:
-
自定义装饰器(如
@check_permissions
、@log_requests
)仍是 Flask 中复用逻辑的推荐方式。 -
在微服务或复杂项目中,可能结合 中间件(Middleware) 或 蓝图(Blueprint)钩子 实现类似功能。
-
-
优势:
-
保持代码简洁,符合 DRY 原则(例如统一处理权限、日志、限流)。
-
-
注意点:
-
过度使用装饰器可能导致代码可读性下降(需权衡)。
-
4. 自定义 URL 转换器
✅ 仍有用,但需求减少
-
现状:
-
Flask 内置的 URL 转换器(如
int
、string
)已覆盖大部分场景,自定义转换器(如@app.url_value_preprocessor
)需求减少。 -
现代 RESTful API 更依赖 标准化的 URL 设计(如
/users/<uuid:user_id>
),而非复杂自定义规则。
-
-
适用场景:
-
需要特殊路由逻辑(如动态子域名、Slug 校验)时仍有用武之地。
-
替代趋势:
复杂路由逻辑可能移交到 API Gateway(如 Kong、Traefik)或前端路由(React/Vue Router)。
总结:哪些原则已过时?
原则 | 是否过时 | 原因 | 现代替代方案 |
---|---|---|---|
@login_required | 仍主流 | 无更优替代 | 兼容 JWT 时需调整 |
Flask-Cache 装饰器 | 已过时 | 项目废弃 | Flask-Caching + Redis |
自定义装饰器 | 仍推荐 | DRY 原则核心 | 可结合中间件 |
自定义 URL 转换器 | 边缘化 | 需求减少 | 标准化路由或 API Gateway |
现代 Flask 开发建议
-
身份验证:
-
传统 SSR:
Flask-Login
+@login_required
。 -
纯 API:
Flask-JWT-Extended
+@jwt_required
。
-
-
缓存:
-
使用
Flask-Caching
+ Redis,而非旧版Flask-Cache
。
-
-
代码复用:
-
优先用装饰器,复杂场景可搭配 蓝图的
before_request
或 中间件。
-
-
路由设计:
-
遵循 RESTful 规范,非必要不自定义 URL 转换器。
-
Flask 的轻量级哲学使其核心原则(如装饰器)依然有效,但工具链(如缓存、身份验证)需跟随生态演进。
六、Blueprints
Summary
-
A blueprint is a collection of views, templates, static files and other extensions that can be applied to an application.
-
Blueprints are a great way to organize your application.
-
In a divisional structure, each blueprint is a collection of views, templates and static files which constitute a particular section of your application.
facebook/__init__.pytemplates/layout.htmlhome/layout.htmlindex.htmlabout.htmlsignup.htmllogin.htmldashboard/layout.htmlnews_feed.htmlwelcome.htmlfind_friends.htmlprofile/layout.htmltimeline.htmlabout.htmlphotos.htmlfriends.htmledit.htmlsettings/layout.htmlprivacy.htmlsecurity.htmlgeneral.htmlviews/__init__.pyhome.pydashboard.pyprofile.pysettings.pystatic/style.csslogo.pngmodels.py
-
In a functional structure, each blueprint is just a collection of views. The templates are all kept together, as are the static files.
-
To use a blueprint, you define it then register it on the application by calling
Flask.register_blueprint().
.
# facebook/__init__.pyfrom flask import Flask
from .views.profile import profileapp = Flask(__name__)
app.register_blueprint(profile)
-
You can define a dynamic URL prefix that will be applied to all routes in a blueprint.
# facebook/views/profile.pyfrom flask import Blueprint, render_templateprofile = Blueprint('profile', __name__, url_prefix='/<user_url_slug>')# [...]
# facebook/__init__.pyfrom flask import Flask
from .views.profile import profileapp = Flask(__name__)
app.register_blueprint(profile, url_prefix='/<user_url_slug>')
-
You can also define a dynamic subdomain for all routes in a blueprint.
-
Refactoring a growing application to use blueprints can be done in five relatively small steps.
1. 蓝图(Blueprint)作为应用组件集合
✅ 仍是核心模式
-
现状:
-
蓝图仍然是 Flask 中模块化组织代码的标准方式,包含视图、模板、静态文件等。
-
在微服务架构中,大型应用可能拆分为多个独立服务,但单体应用内仍依赖蓝图分模块。
-
-
优势:
-
解耦功能模块(如
auth_bp
、admin_bp
),支持多人协作开发。
-
-
现代调整:
-
结合 工厂模式(Application Factory) 动态注册蓝图,更适合测试和扩展。
-
2. 组织方式:功能型(Functional) vs 分区型(Divisional)
⚠️ 分区型(Divisional)更主流,功能型(Functional)边缘化
-
分区型(Divisional):
-
仍广泛使用:每个蓝图是一个完整功能模块(如
users_bp
包含视图、模板、静态文件)。 -
适合大多数项目,符合“高内聚低耦合”原则。
-
-
功能型(Functional):
-
基本过时:将模板/静态文件全局集中管理,视图按逻辑拆分(如
auth_views_bp
、profile_views_bp
)。 -
缺点:模板和静态文件难以维护,不符合组件化趋势。
-
现代实践:
优先用分区型,甚至进一步拆分为 独立 Python 包(如flask-admin
的插件化设计)。
3. 动态 URL 前缀/子域名
✅ 仍在使用,但需求减少
-
动态 URL 前缀(
url_prefix
):-
常用:如 API 版本控制(
/api/v1/
)或多租户路径隔离(/tenant/<id>/
)。
-
-
动态子域名(
subdomain
):-
边缘化:现代架构中,子域名路由通常由 反向代理(Nginx) 或 API Gateway(如 Kong)处理,而非应用层。
-
适用场景:
简单项目可直接用 Flask 子域名功能,复杂场景移交基础设施层。
4. 重构为蓝图的步骤
✅ 仍是标准流程
-
现状:
-
将大型应用拆分为蓝图的步骤(如逐步迁移视图、模板)未过时,但现代项目更倾向于 从一开始设计蓝图。
-
-
现代改进:
-
结合 模块化工厂模式(
create_app()
)动态注册蓝图,支持环境差异化配置。
-
5. 蓝图的注册方式(register_blueprint
)
✅ 语法未变,但注册时机演进
-
传统方式:
-
直接在模块层调用
app.register_blueprint()
。
-
-
现代方式:
-
在 应用工厂 中注册,或通过 插件系统(如
flask-sqlalchemy
的init_app()
模式)延迟绑定。
-
总结:哪些原则已过时?
原则 | 是否过时 | 原因 | 现代替代方案 |
---|---|---|---|
蓝图作为模块化单元 | 仍主流 | 无可替代 | 无 |
功能型(Functional)结构 | 已过时 | 维护性差 | 分区型(Divisional) |
动态子域名 | 边缘化 | 由基础设施处理 | Nginx/API Gateway |
直接全局注册蓝图 | 不推荐 | 缺乏灵活性 | 应用工厂模式 |
现代 Flask 蓝图最佳实践
-
设计阶段:
-
按 业务边界 划分蓝图(如
auth_bp
、order_bp
),每个蓝图包含自己的视图、模板、静态文件。
-
-
代码结构:
/app ├── /auth # 蓝图模块 │ ├── __init__.py # 创建蓝图对象 │ ├── routes.py # 视图 │ ├── templates/ # 蓝图专属模板 │ └── static/ # 蓝图专属静态文件 ├── /orders │ └── ... # 同上 └── create_app.py # 应用工厂
-
注册时机:
-
在
create_app()
中动态注册蓝图,支持测试和配置隔离:
def create_app(config):app = Flask(__name__)app.register_blueprint(auth_bp)app.register_blueprint(orders_bp, url_prefix='/orders')return app
-
进阶场景:
-
将蓝图发布为 独立 PyPI 包(如
flask-admin
),通过pip
安装复用。
-
何时不需要蓝图?
-
极简应用:单文件 Flask 应用(如原型开发)。
-
微服务架构:功能已拆分为独立服务,单体内部无需再分蓝图。
Flask 蓝图的核心思想(模块化)并未过时,但实现细节需结合现代架构(如工厂模式、基础设施分层)优化。
七、Templates
Summary
-
Use Jinja for templating.
-
Jinja has two kinds of delimeters:
{% ... %}
and{{ ... }}
. The first one is used to execute statements such as for-loops or assign values, the latter prints the result of the contained expression to the template.
{# _myapp/templates/layout.html_ #}<!DOCTYPE html>
<html lang="en"><head><title>{% block title %}{% endblock %}</title></head><body>{% block body %}<h1>This heading is defined in the parent.</h1>{% endblock %}</body>
</html>
-
Templates should go in myapp/templates/ — i.e. a directory inside of the application package.
-
I recommend that the structure of the templates/ directory mirror the URL structure of the app.
-
You should have a top-level layout.html in myapp/templates as well as one for each section of the site. The latter extend the former.
templates/layout.htmlindex.htmlabout.htmlprofile/layout.htmlindex.htmlphotos.htmladmin/layout.htmlindex.htmlanalytics.html
-
Macros are like functions made-up of template code.
{# myapp/templates/layout.html #}{% from "macros.html" import nav_link with context %}
<!DOCTYPE html>
<html lang="en"><head>{% block head %}<title>My application</title>{% endblock %}</head><body><ul class="nav-list">{{ nav_link('home', 'Home') }}{{ nav_link('about', 'About') }}{{ nav_link('contact', 'Get in touch') }}</ul>{% block body %}{% endblock %}</body>
</html>
-
Filters are functions made-up of Python code and used in templates.
1. 使用 Jinja2 作为模板引擎
✅ 仍是 Flask 的黄金标准
-
现状:
-
Jinja2 仍是 Flask 默认且官方推荐的模板引擎,与 Flask 深度集成。
-
现代前端框架(如 React/Vue)的兴起减少了服务端渲染(SSR)的使用,但 Jinja2 在 SSR 场景中不可替代。
-
-
优势:
-
语法简洁,支持模板继承、宏等高级功能。
-
适合内容型网站(如博客、CMS)或需要 SEO 的页面。
-
-
注意点:
-
纯 API 项目可能完全不需要 Jinja2。
-
2. Jinja2 分隔符 {% ... %}
和 {{ ... }}
✅ 语法未变,仍是核心
-
现代调整:
-
新增
{% ... %}
的扩展用法(如{% set x = namespace() %}
),但基础逻辑不变。 -
前端开发者可能更熟悉 JSX/Vue 的
{{ }}
,但 Jinja2 的语义保持一致。
-
3. 模板目录应位于 myapp/templates/
⚠️ 仍适用,但灵活性增加
-
传统实践:
-
Flask 默认从
templates/
加载模板,符合“约定优于配置”原则。
-
-
现代演进:
-
可通过
template_folder
参数自定义路径(如Flask(__name__, template_folder="../frontend/templates")
)。 -
大型项目可能将模板拆分为 独立包(如共享模板库)。
-
建议:除非有特殊需求,否则仍推荐默认目录结构。
4. 模板目录结构应镜像 URL 结构
❌ 已过时(仅适用于简单项目)
-
过时原因:
-
现代项目更倾向于 按功能模块组织模板(如
templates/auth/login.html
),而非严格匹配 URL(如/auth/login
)。 -
RESTful API 和前端框架的普及使得 URL 结构与模板解耦。
-
-
例外:
-
内容型网站(如新闻分类)可能仍保留部分镜像结构。
-
5. 顶层 layout.html
+ 区块模板继承
✅ 仍是最佳实践
-
现状:
-
基模板(
layout.html
)定义通用结构(如导航栏、页脚),子模板通过{% extends %}
和{% block %}
覆盖特定区块。 -
与前端框架的“组件化”思想一致(如 Vue 的
<slot>
)。
-
-
优势:
-
避免重复代码,符合 DRY 原则。
-
6. 宏(Macros)作为模板函数
✅ 仍有用,但使用减少
-
现状:
-
宏适合复用模板片段(如渲染表单字段),但在以下场景中被替代:
-
前端框架(如 React/Vue)通过组件化实现更强大的复用。
-
复杂逻辑更适合移回后端(通过 API 返回结构化数据)。
-
-
-
适用场景:
-
服务端渲染中需要重复使用的 UI 元素(如分页控件)。
-
7. 过滤器(Filters)
✅ 仍有用,但需谨慎使用
-
现状:
-
内置过滤器(如
|safe
、|capitalize
)仍常用。 -
自定义过滤器适合简单文本处理(如日期格式化),但复杂逻辑应优先在 后端处理 或通过 前端工具库(如
day.js
)。
-
-
风险:
-
过度使用过滤器会导致模板臃肿,违背“逻辑与表现分离”原则。
-
总结:哪些原则已过时?
原则 | 是否过时 | 原因 | 现代替代方案 |
---|---|---|---|
使用 Jinja2 | 仍主流 | 无更优替代 | 纯 API 项目可省略 |
分隔符语法 | 未变 | 语法稳定 | 无 |
默认 templates/ 目录 | 仍适用 | 约定优于配置 | 支持自定义路径 |
模板镜像 URL 结构 | 已过时 | 灵活性差 | 按功能模块组织 |
模板继承(layout.html ) | 仍最佳实践 | DRY 原则 | 类似前端组件化 |
宏(Macros) | 边缘化 | 前端框架替代 | Vue/React 组件 |
过滤器(Filters) | 有限使用 | 逻辑应后移 | 后端处理或前端工具库 |
现代 Jinja2 模板开发建议
-
组织方式:
-
按功能模块划分模板目录(如
templates/auth/
、templates/blog/
),而非机械匹配 URL。
-
-
逻辑分离:
-
复杂计算通过 视图函数 预处理,模板仅负责渲染。
-
-
组件化:
-
使用
{% include %}
或宏封装可复用 UI 片段(如按钮、卡片)。
-
-
安全性:
-
始终用
|safe
标记可信的 HTML 内容,避免 XSS。
-
-
结合现代工具:
-
开发阶段启用
TEMPLATES_AUTO_RELOAD=True
自动刷新模板。
-
何时不用 Jinja2?
纯 API 项目(无服务端渲染)。
前后端完全分离(前端使用 React/Vue)。
Jinja2 的核心功能(模板继承、变量渲染)依然不可替代,但需根据项目架构调整使用方式。
八、Static files
Summary
-
Static files go in the static/ directory.
myapp/__init__.pystatic/templates/views/models.py
run.py
-
Separate third-party libraries from your own static files.
static/css/lib/bootstrap.cssstyle.csshome.cssadmin.cssjs/lib/jquery.jshome.jsadmin.jsimg/logo.svgfavicon.ico
-
Specify the location of your favicon in your templates.
-
Use Flask-Assets to insert static files in your templates.
# myapp/util/assets.pyfrom flask_assets import Bundle, Environment
from .. import appbundles = {'home_js': Bundle('js/lib/jquery-1.10.2.js','js/home.js',output='gen/home.js'),'home_css': Bundle('css/lib/reset.css','css/common.css','css/home.css',output='gen/home.css'),'admin_js': Bundle('js/lib/jquery-1.10.2.js','js/lib/Chart.js','js/admin.js',output='gen/admin.js'),'admin_css': Bundle('css/lib/reset.css','css/common.css','css/admin.css',output='gen/admin.css')
}assets = Environment(app)assets.register(bundles)
-
Flask-Assets can compile, combine and compress your static files.
仍然适用的原则 ✅
-
Static files go in the static/ directory
-
Flask 仍然默认使用
static/
目录存放静态文件,这是官方推荐的做法
-
-
Separate third-party libraries from your own static files
-
仍然建议将第三方库(如 jQuery、Bootstrap)和自己的静态文件分开管理
-
-
Specify the location of your favicon in your templates
-
仍然需要在模板中正确指定 favicon 路径
-
部分过时/有更好替代方案的原则 ⚠️
-
Use Flask-Assets to insert static files in your templates
-
仍然可用但不是主流选择,现代前端工作流更倾向于使用:
-
Webpack/Vite 等现代打包工具
-
Flask 原生
url_for('static', ...)
方式 -
CDN 直接引入前端库
-
-
-
Flask-Assets can compile, combine and compress your static files
-
功能仍然存在但不再是首选方案,现代替代方案包括:
-
使用 npm/yarn/pnpm + Webpack/Vite/Rollup
-
使用 Flask-Minify 等专门压缩扩展
-
云服务(如 AWS CloudFront)自动压缩
-
-
现代补充建议 ✨
-
考虑使用
flask-static-compress
或flask-minify
进行压缩 -
对于复杂项目,建议采用前后端分离架构
-
静态文件建议通过 CDN 分发
-
现代前端框架(React/Vue)通常有自己的静态文件处理方式
Flask-Assets 虽然仍能工作,但在 2023 年后的新项目中已经很少被用作主要解决方案,除非是在维护传统项目。
九、Storing data
Summary
-
Use SQLAlchemy to work with relational databases.
# ourapp/__init__.pyfrom flask import Flask
from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__, instance_relative_config=True)app.config.from_object('config')
app.config.from_pyfile('config.py')db = SQLAlchemy(app)
# ourapp/models.pyfrom . import dbclass Engine(db.Model):# Columnsid = db.Column(db.Integer, primary_key=True, autoincrement=True)title = db.Column(db.String(128))thrust = db.Column(db.Integer, default=0)
-
Use Flask-SQLAlchemy to work with SQLAlchemy.
-
Alembic helps you migrate your data between schema changes.
ourapp/alembic.inialembic/env.pyREADMEscript.py.makoversions/3512b954651e_add_account.py2b1ae634e5cd_add_order_id.py3adcc9a56557_rename_username_field.pymyapp/__init__.pyviews.pymodels.pytemplates/run.pyconfig.pyrequirements.txt
-
You can use NoSQL databases with Flask, but the methods and tools vary between engines.
-
Back up your data!
仍然适用的原则 ✅
-
Use SQLAlchemy to work with relational databases
-
SQLAlchemy 仍然是 Python 生态中最主流、最强大的 ORM,Flask 项目中的首选方案
-
核心功能(ORM/SQL Expression)设计经受了时间考验
-
-
Use Flask-SQLAlchemy to work with SQLAlchemy
-
Flask-SQLAlchemy 仍然是官方推荐的集成方案(最新版本 3.1.x)
-
提供了
db.session
管理和 Flask 集成等便利功能
-
-
Alembic helps you migrate your data between schema changes
-
Alembic 仍然是 SQLAlchemy 生态的标准迁移工具
-
现代改进:支持异步(Alembic 1.11+)、更好的 DDL 事务控制
-
-
Back up your data!
-
永恒真理,现在更多通过云数据库的自动备份功能实现(如 AWS RDS 快照)
-
需要更新的原则 ⚠️
-
You can use NoSQL databases with Flask, but the methods and tools vary between engines
-
仍然正确,但现代变化:
-
MongoDB:推荐官方驱动
PyMongo
(Flask-PyMongo 已不维护) -
Redis:直接使用
redis-py
,部分场景可用Flask-Caching
-
新兴数据库:如 ClickHouse 有专用 Python 驱动
-
-
趋势:NoSQL 不再强调 "Flask 扩展",而是直接使用各数据库的官方 SDK
-
现代补充建议 ✨
-
异步支持:
-
SQLAlchemy 2.0+ 全面支持 async(需配合
asyncpg
/aiomysql
) -
Flask 本身不支持异步,但可通过 Quart(Flask 异步克隆)实现
-
-
替代方案:
-
简单项目可考虑
PeeWee
或SQLModel
(SQLAlchemy + Pydantic) -
Django 开发者可能更喜欢
Flask-Marshmallow
序列化
-
-
云原生趋势:
-
无服务器场景考虑 Serverless 数据库(如 PlanetScale、Neon)
-
分布式 SQL(如 CockroachDB)有完善 SQLAlchemy 支持
-
-
开发体验:
-
使用
Flask-Migrate
简化 Alembic 操作(flask db migrate
) -
推荐
SQLAlchemy 2.0
声明式表配置(更简洁的语法)
-
-
安全建议:
-
一定要启用 SQLAlchemy 的
echo=False
生产环境 -
使用
scoped_session
避免多线程问题
-
过时/不推荐的做法 🚫
-
避免旧版 SQLAlchemy 1.3 的写法(如
query.get()
已弃用) -
不再推荐使用
Flask-MongoEngine
等封装过度的 NoSQL 扩展 -
避免手动拼接 SQL(SQLAlchemy Core 已能处理绝大多数场景)
现代 Flask 项目数据库选择建议:PostgreSQL + SQLAlchemy 2.0 + Alembic 仍是黄金组合。
十、Handling forms
Summary
-
Forms can be scary from a security perspective.
# ourapp/forms.pyfrom flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Emailclass EmailPasswordForm(Form):email = StringField('Email', validators=[DataRequired(), Email()])password = PasswordField('Password', validators=[DataRequired()])
-
WTForms (and Flask-WTF) make it easy to define, secure and render your forms.
-
Use the CSRF protection provided by Flask-WTF to secure your forms.
{# ourapp/templates/login.html #}{% extends "layout.html" %}
<html><head><title>Login Page</title></head><body><form action="{{ url_for('login') }}" method="post"><input type="text" name="email" /><input type="password" name="password" />{{ form.csrf_token }}</form></body>
</html>
-
You can use Flask-WTF to protect AJAX calls against CSRF attacks too.
-
Define custom form validators to keep validation logic out of your views.
-
Use the WTForms field rendering to render your form’s HTML so you don’t have to update it every time you make some changes to the form definition.
仍然适用的原则 ✅
-
Forms can be scary from a security perspective
-
表单安全仍是重中之重(CSRF/XSS/SQL 注入等风险依然存在)
-
-
Use the CSRF protection provided by Flask-WTF to secure your forms
-
Flask-WTF 的 CSRF 保护仍是标准方案(最新版本 1.2.x)
-
现代补充:REST API 推荐改用 JWT/OAuth2 + SameSite cookies
-
-
Define custom form validators to keep validation logic out of your views
-
验证逻辑与视图分离仍是最佳实践
-
现代扩展:可结合 Pydantic 进行更复杂的验证
-
需要更新的原则 ⚠️
-
WTForms (and Flask-WTF) make it easy to define, secure and render your forms
-
仍然可用但不再是唯一选择,现代替代方案:
-
前端框架(React/Vue)直接处理表单 + Flask 仅作 API 验证
-
使用 Pydantic 进行数据验证(尤其适合 API 项目)
-
简单场景可用
flask.request.get_json()
直接处理
-
-
-
You can use Flask-WTF to protect AJAX calls against CSRF attacks too
-
仍然有效但现代方案更倾向于:
-
对 API 使用 JWT + CORS 限制
-
启用
SameSite=Strict
cookie 策略 -
框架内置 CSRF(如 Next.js/Angular 自带防护)
-
-
-
Use the WTForms field rendering to render your form’s HTML
-
服务器端渲染表单逐渐减少,现代趋势:
-
前端动态渲染(React/Vue/Svelte 表单组件库)
-
仅用 WTForms 做验证,前端单独实现 UI
-
HTMX 等新技术实现渐进式增强
-
-
现代补充建议 ✨
-
混合验证架构:
# 结合 Pydantic 和 WTForms 的优点 from pydantic import BaseModel from flask_wtf import FlaskFormclass APIModel(BaseModel): # API 请求验证name: strage: intclass WebForm(FlaskForm): # 传统网页表单name = StringField(validators=[DataRequired()])
-
安全增强:
-
始终启用
WTF_CSRF_ENABLED = True
(默认已开启) -
对敏感操作添加二次验证(如 CAPTCHA)
-
-
现代替代工具:
-
前端表单:Formik(React)、VeeValidate(Vue)
-
验证库:Pydantic、marshmallow
-
安全:Flask-Talisman(强制 HTTPS/HSTS)
-
-
性能优化:
-
对静态表单考虑缓存渲染结果
-
使用
flask-caching
缓存验证规则
-
过时/不推荐的做法 🚫
-
避免完全依赖 WTForms 渲染前端(难以适应现代 UI 需求)
-
不要手动拼接 HTML 表单(易导致 XSS 漏洞)
-
避免在 AJAX 中直接提交
application/x-www-form-urlencoded
(推荐 JSON)
当前推荐方案
场景 | 推荐工具 |
---|---|
传统多页应用 | Flask-WTF + WTForms |
SPA 前后端分离 | Pydantic + 前端表单库 |
混合应用(HTMX) | WTForms 验证 + 部分渲染 |
关键结论:WTForms 仍然安全可靠,但现代项目更倾向于将表单逻辑交给前端,后端专注数据验证。对于新项目,建议优先考虑 Pydantic + 前端框架的组合。
十一、Patterns for handling users
Summary
-
Use the itsdangerous package to create and validate tokens sent to an email address.
# ourapp/util/security.pyfrom itsdangerous import URLSafeTimedSerializerfrom .. import appts = URLSafeTimedSerializer(app.config["SECRET_KEY"])
# ourapp/views.pyfrom flask import redirect, render_template, url_forfrom . import app, db
from .forms import EmailPasswordForm
from .util import ts, send_email@app.route('/accounts/create', methods=["GET", "POST"])
def create_account():form = EmailPasswordForm()if form.validate_on_submit():user = User(email = form.email.data,password = form.password.data)db.session.add(user)db.session.commit()# Now we'll send the email confirmation linksubject = "Confirm your email"token = ts.dumps(self.email, salt='email-confirm-key')confirm_url = url_for('confirm_email',token=token,_external=True)html = render_template('email/activate.html',confirm_url=confirm_url)# We'll assume that send_email has been defined in myapp/util.pysend_email(user.email, subject, html)return redirect(url_for("index"))return render_template("accounts/create.html", form=form)
{# ourapp/templates/email/activate.html #}Your account was successfully created. Please click the link below<br>
to confirm your email address and activate your account:<p>
<a href="{{ confirm_url }}">{{ confirm_url }}</a>
</p><p>
--<br>
Questions? Comments? Email hello@myapp.com.
</p>
-
You can use these tokens to validate emails when a user creates an account, changes their email or forgets their password.
# ourapp/views.py@app.route('/confirm/<token>')
def confirm_email(token):try:email = ts.loads(token, salt="email-confirm-key", max_age=86400)except:abort(404)user = User.query.filter_by(email=email).first_or_404()user.email_confirmed = Truedb.session.add(user)db.session.commit()return redirect(url_for('signin'))
-
Authenticate users using the Flask-Login extension to avoid dealing with a bunch of session management stuff yourself.
-
Always think about how a malicious user could abuse your app to do things that you didn’t intend.
仍然适用的原则 ✅
-
Authenticate users using Flask-Login
-
Flask-Login(最新版本 0.6.x)仍是管理用户会话的事实标准
-
核心功能稳定:
@login_required
、current_user
、remember_me
等 -
现代补充:支持自定义用户加载器(包括异步场景)
-
-
Always think about security
-
"考虑恶意用户行为"是永恒原则,现代威胁模型新增:
-
API 滥用(暴力破解/爬虫)→ 需增加速率限制(Flask-Limiter)
-
密码 spraying 攻击→ 强制 MFA(如 Flask-Dance 支持 OAuth)
-
供应链攻击→ 依赖项扫描(pip-audit)
-
-
需要更新的原则 ⚠️
-
Use itsdangerous for email tokens
-
仍然可用但不再是首选方案,现代替代方案:
-
专用令牌库:PyJWT(RFC 7519 标准 JWT)
-
安全增强:使用
cryptography
直接生成加密令牌 -
云服务:AWS Cognito/Auth0 等托管服务
-
-
仅推荐 itsdangerous 用于简单场景(如开发环境)
-
现代补充建议 ✨
认证架构升级
# 现代认证组合示例(2024)
from flask_jwt_extended import JWTManager # REST API
from flask_principal import Principal # 权限管理
from authlib.integrations.flask_client import OAuth # 第三方登录jwt = JWTManager(app) # 替代部分 itsdangerous 场景
oauth = OAuth(app)
关键实践
-
密码重置/邮件验证
-
改用 时间受限的 JWT(
flask-jwt-extended
) -
必须使用 一次性令牌(即使 itsdangerous 也需自行实现)
-
-
会话管理
-
启用
SESSION_PROTECTION = "strong"
(Flask-Login) -
生产环境必须使用
Secure
/HttpOnly
cookies
-
-
现代威胁防护
# 安全头设置(Flask-Talisman) talisman = Talisman(app,content_security_policy=...,force_https=True )
-
审计工具
-
使用
bandit
扫描安全漏洞 -
依赖项检查:
safety check
或 GitHub Dependabot
-
过时/不推荐的做法 🚫
-
避免直接使用 itsdangerous 处理敏感操作(如密码重置)
-
不要自行实现加密算法(应使用
passlib
或bcrypt
) -
避免将 Flask-Login 用于纯 API 项目(应改用 JWT)
2024 年推荐方案
场景 | 工具选择 |
---|---|
传统网页应用 | Flask-Login + Flask-WTF CSRF |
REST API | flask-jwt-extended + OAuth2 |
邮件验证/密码重置 | PyJWT(而非 itsdangerous) |
第三方登录 | Authlib/OAuthLib |
核心建议:
-
新项目优先考虑 JWT + OAuth 2.0 生态
-
维护旧项目时可继续使用 itsdangerous,但需增加速率限制
-
必须实施 密码哈希(argon2id/bcrypt) + HTTPS 强制跳转
十二、Deployment
Summary
-
Three good choices for hosting Flask apps are AWS EC2, Heroku and Digital Ocean.
-
The basic deployment stack for a Flask application consists of the app, an application runner like Gunicorn and a reverse proxy like Nginx.
(ourapp)$ gunicorn rocket:app
2014-03-19 16:28:54 [62924] [INFO] Starting gunicorn 18.0
2014-03-19 16:28:54 [62924] [INFO] Listening at: http://127.0.0.1:8000 (62924)
2014-03-19 16:28:54 [62924] [INFO] Using worker: sync
2014-03-19 16:28:54 [62927] [INFO] Booting worker with pid: 62927
(ourapp)$ gunicorn rocket:app -p rocket.pid -D
(ourapp)$ cat rocket.pid
63101
(ourapp)$ kill -HUP `cat rocket.pid`
(ourapp)$ kill `cat rocket.pid`
-
Gunicorn should sit behind Nginx and listen on 127.0.0.1 (internal requests) not 0.0.0.0 (external requests).
-
Use Werkzeug’s ProxyFix to handle the appropriate proxy headers in your Flask application.
仍然适用的原则 ✅
-
基础部署架构(App → Gunicorn → Nginx)
-
传统虚拟机部署仍保持此结构,但现代方案更倾向于容器化
-
新增要求:Nginx 现在需强制配置
HTTP/2
和TLS 1.3
-
-
Gunicorn 监听本地端口
-
安全规范仍然要求:生产环境必须绑定
127.0.0.1
而非0.0.0.0
-
现代补充:Kubernetes 环境下改为通过 Service 暴露
-
-
Werkzeug 的 ProxyFix
-
仍然需要处理反向代理头,但现代方案:
from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
-
新增要求:必须显式配置
x_for/x_proto
数量(防伪造)
-
需要更新的原则 ⚠️
-
三大托管服务推荐(EC2/Heroku/Digital Ocean)
-
Heroku:已不再提供免费层(2022年11月取消),性价比下降
-
Digital Ocean:现更推荐其 App Platform(托管容器服务)
-
AWS EC2:仍是主流但非最优选择,现代替代方案:
-
容器服务:AWS ECS/EKS、Google Cloud Run
-
Serverless:AWS Lambda(Zappa框架)、Vercel
-
边缘部署:Fly.io、Cloudflare Workers
-
-
现代补充建议 ✨
部署架构演进
关键实践升级
-
运行时选择
-
同步应用:仍可用 Gunicorn + gevent
-
异步应用:改用 Uvicorn(ASGI 服务器,支持 HTTP/2)
-
-
安全强化
# Nginx 现代配置片段 location / {proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header X-Forwarded-Proto $scheme;# 必须设置严格 CSPadd_header Content-Security-Policy "default-src 'self'"; }
-
基础设施即代码
-
使用 Terraform/Pulumi 管理云资源
-
部署工具:GitHub Actions > Fabric/Capistrano
-
-
性能优化
-
静态文件移交 CDN(Cloudflare/R2)
-
启用 Brotli 压缩替代 gzip
-
过时/不推荐的做法 🚫
-
避免直接部署裸机/虚拟机(除非有特殊需求)
-
不要使用
flask run
生产环境(仍常见于教程但极不安全) -
避免手动配置服务器(应使用 Docker + CI/CD 自动化)
2024 年推荐方案
场景 | 推荐方案 | 优势 |
---|---|---|
快速原型 | Fly.io/Render | 5分钟部署,免费额度 |
传统应用 | Docker + EC2 | 平衡控制力与成本 |
高流量服务 | Kubernetes + GCP | 自动伸缩 |
Serverless | AWS Lambda + API Gateway | 按需计费 |
重要趋势:
-
容器化已成默认选择(即使小型项目)
-
Serverless 方案成熟(Cold Start 问题显著改善)
-
边缘计算兴起(如 Cloudflare Workers 支持 Python)
建议新项目优先考虑:Docker → 托管容器服务(如 Fly.io) 的路径,既保持开发一致性,又降低运维复杂度。
相关文章:
【Flask】Explore-Flask:早期 Flask 生态的实用指南
开源项目:explore-flask/README.rst at master rpicard/explore-flask (github.com) 一、Coding conventions Summary Try to follow the coding style conventions laid out in PEP 8. Try to document your app with docstrings as defined in PEP 257. def…...
Canvas入门教程!!【前端】
目录 canvas是什么?使用场景:canvas使用:引入:获取2D的上下文:坐标轴: 绘制:beginPath() :moveTo() :lineTo():stroke():fillRect() :strokeStyle 属性&#…...
通过规范化模型自训练增强医学图像分割中的无监督域自适应|文献速递-深度学习医疗AI最新文献
Title 题目 Enhancing source-free domain adaptation in Medical Image Segmentationvia regulated model self-training 通过规范化模型自训练增强医学图像分割中的无监督域自适应 01 文献速递介绍 深度卷积神经网络对训练数据分布(源域)和测试数…...
Linux常见指令介绍中(入门级)
1. man 在Linux中,man命令是用于查看命令手册页的工具,它可以帮助用户了解各种命令、函数、系统调用等的详细使用方法和相关信息。 用法:在终端中输入man加上要查询的命令或工具名称,例如man ls,就会显示ls命令的手册…...
一文详解卷积神经网络中的卷积层和池化层原理 !!
文章目录 前言 一、卷积核大小(Kernel Size) 1. 卷积核大小的作用 2. 常见的卷积核大小 3. 选择卷积核大小的原则 二、步长(Stride) 1. Stride的作用 三、填充(Padding) 1. 填充的作用 四、通道数ÿ…...
神经网络直接逆控制:神经网络与控制的结合入门级结合
目录 1. 前言 2. 什么是直接逆控制? 2.1 直接逆控制的优点 2.2 直接逆控制的局限性 3. 直接逆控制的实现步骤 3.1 数据准备 3.2 神经网络设计 3.3 训练神经网络 3.4 控制实现 4. 使用 PyTorch 实现直接逆控制 4.1 问题描述 4.2 数据生成 4.3 神经网络设…...
使用tabs组件搭建UI框架
本节任务 使用tabs组件搭建ui框架 包含页签:首页、动态、发布,会员购、我的。 涉及内容: Tabs、TabContent组件Builder装饰器属性模型封装,包括:接口、枚举、常量 界面原型 1 Tabs布局 在MainPage(如果…...
jmeter跟踪重定向和自动重定向有什么区别?
在 JMeter 中,跟踪重定向和自动重定向有以下区别: 概念 跟踪重定向:指的是 JMeter 会按照服务器返回的重定向信息,继续发送请求到重定向的目标地址,并记录下整个重定向的过程,包括重定向的地址、响应信息…...
unity3d实现物体闪烁
unity3d实现物体闪烁,代码如下: using UnityEngine;public class Test : MonoBehaviour {//创建一个常量,用来接收时间的变化值private float shake;//通过控制物体的MeshRenderer组件的开关来实现物体闪烁的效果private MeshRenderer BoxColliderClick…...
(三十)安卓开发中的MVP模式详解
在安卓开发中,MVP(Model-View-Presenter) 是一种常见的软件架构模式,它通过将应用程序的逻辑与用户界面分离,使得代码更加模块化、易于维护和测试。本文将详细讲解MVP模式的组成部分、工作流程、优点,并结合…...
独立ADC和MCU中ADC模块的区别
以图中两种方案为例: 使用独立ADC和使用MCU的内部ADC来实现模数转换,有什么性能、技术上的区别吗? 集成和独立芯片各有优劣势: 1、集成的节约了板子空间,减少了外围设计。工艺也不一样,集成的工艺相对高一…...
微软Entra新安全功能引发大规模账户锁定事件
误报触发大规模锁定 多家机构的Windows管理员报告称,微软Entra ID新推出的"MACE"(泄露凭证检测应用)功能在部署过程中产生大量误报,导致用户账户被大规模锁定。这些警报和锁定始于昨夜,部分管理员认为属于误…...
Ray Tracing(光线追踪)与 Ray Casting(光线投射)
Ray Casting(光线投射) 定义:一种从观察点(如摄像机)向场景中每个像素投射单条光线,找到最近可见物体的渲染技术。 核心任务:确定像素对应的物体表面颜色,通常仅计算直接光照&#…...
Shell脚本-变量的分类
在Shell脚本编程中,变量是存储数据的基本单位。它们可以用来保存字符串、数字甚至是命令的输出结果。正确地定义和使用变量能够极大地提高脚本的灵活性与可维护性。本文将详细介绍Shell脚本中变量的不同分类及其应用场景,帮助你编写更高效、简洁的Shell脚…...
go for 闭环问题【踩坑记录】
Go 中的for 循环闭包问题,是每个 Go 程序员几乎都踩过的坑,也是面试和实际开发中非常容易出错和引起 bug 的地方。这里我会通过原理、示例、修正方法、背后机制等角度详细为你讲解。 一、问题描述 当你在 for 循环里写匿名函数(闭包…...
【分布式理论17】分布式调度3:分布式架构-从中央式调度到共享状态调度
文章目录 一、中央式调度器1. 核心思想2. 工作流程3. 优缺点4. **典型案例:Google Borg** 二、两级调度器1. **核心思想**2. **工作流程**3. 优缺点4. **典型案例:Hadoop YARN** 三、共享状态调度器1. **核心思想**2. **工作流程**3. 优缺点4. **典型案例…...
Java高频面试之并发编程-04
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:调用 start()方法时会执行 run()方法,那为什么不直接调用 run()方法? 多线程中调用 start() 方法…...
2025Java面试指南(附答案)
Java全家桶 Java基础 1. Java为什么被称为平台无关性语言? 2. 解释下什么是面向对象?面向对象和面向过程的区别 3. 面向对象的三大特性?分别解释下? 4. Java 中的参数传递时传值呢?还是传引用? 5. JD…...
springboot对接阿里云大模型
阿里云百炼文档地址: 百炼控制台 设置账号 首先跟着文档设置账号,新建一个api key 文档地址: 百炼控制台 对接会话API 你可以使用sdk来对接,但没有必要,因为所有接口对接都是http形式的,直接使用http库来对接就行了ÿ…...
理性决策与情绪偏差
“在愤怒中做决策,你会在懊悔中收拾残局。”—本杰明富兰克林 在情绪激动时,我们往往容易做出冲动的决定。但等情绪平复,回过头来看,常常会发现这些决定并不如我们当初所想的那样明智。诺贝尔经济学奖得主在其行为经济学研究中提…...
基于LLM的响应式流式处理实践:提升用户体验的关键技术
基于LLM的响应式流式处理实践:提升用户体验的关键技术 前言:当AI生成遇到用户等待焦虑 在人工智能应用井喷式发展的今天,大语言模型(LLM)的文本生成延迟问题始终是开发者需要直面的挑战。想象这样一个场景࿱…...
2025年渗透测试面试题总结-拷打题库09(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库09 1. Linux系统加固降权思路 2. 系统后门检测工具 3. 绕过CDN获…...
批量替换多个 Word 文档中的指定图片
在 Word 文档中,我们可以插入各种各样的图片,比如插入 logo、插入设计图、施工图等等。在某些情况下,我们也会碰到需要将 Word 文档中某张图片替换成其它图片的场景,比如将旧的 Logo 替换成新的 Logo。当我们有大量的 Word 文档需…...
海外版高端Apple科技汽车共享投资理财系统
这一款PHP海外版高端Apple、科技汽车、共享投资理财系统phplaravel框架。...
【Unity iOS打包】报错解决记录
打包报错1: Invalid Bundle. The bundle at ProductName.app/Frameworks/UnityFramework.framework contains disallowed file Frameworks. (ID: 87a95518-52e2-4ce0-983d-aab8d8006f11) 解决: Target > UnityFramework > Build Settings > Bu…...
新能源汽车零部件功率级测试方案搭建研究
摘要:本文旨在针对新能源汽车核心零部件功率级测试需求,提出基于Python与PyVISA的自动化测试方案。通过集成主流设备(如Keysight 34980A、功率分析仪等),构建多协议兼容(CAN、RS485等)的测试平台…...
DeepSeek与WPS的动态数据可视化图表构建
摘要 在数据驱动决策的时代,动态数据可视化对于信息的高效传递与分析至关重要。本文聚焦于利用DeepSeek和WPS实现近百种动态数据可视化图表的技术应用,详细阐述其操作流程、技术原理及潜在价值。通过深入剖析这一技术组合的应用场景与实践意义࿰…...
XCTF-web(五)
Web_php_unserialize 当通过KaTeX parse error: Expected group after _ at position 42: …erialize,触发魔术方法_̲_wakeup和__destr…this->file)输出文件内容,若KaTeX parse error: Expected group after _ at position 17: …ile可控࿰…...
数字ic后端设计从入门到精通2(含fusion compiler, tcl教学)
上篇回顾 上一篇文章需要讨论了net,pin的基础用法,让我们来看一下高级一点的用法 instance current_instance current_instance 是 Synopsys 工具(如 Fusion Compiler 或 Design Compiler)中用于在设计层次结构中导航的关键命令。它允许用…...
Vue2集成ElementUI实现左侧菜单导航
文章目录 简介静态导航安装element-ui,vue-router,vuex编写router/index.jsmain.js中引入elementui,router编写左侧导航返回的菜单数据 动态导航编写router/index.js左侧菜单通过for循环生成通过for循环递归生成 store/index.jsmain.js中引入store登录页面代码菜单返回数据 总结…...
Flask API 项目 Swagger 版本打架不兼容
Flask API 项目 Swagger 版本打架不兼容 1. 问题背景 在使用 Flask 3.0.0 时遇到以下问题: 安装 flask_restful_swagger 时,它强制将 Flask 降级到 1.1.4,并导致其他依赖(如 flask-sqlalchemy、flask-apispec)出现版…...
spark和Hadoop的区别和联系
区别 计算模型 Hadoop:主要基于 MapReduce 计算模型,将任务分为 Map 和 Reduce 两个阶段,适合处理大规模的批处理数据,但在处理迭代式计算和交互式查询时性能相对较差。Spark:基于内存的分布式计算框架,采…...
Unity接入安卓SDK(2)接入方式
1 方式一:SDK打成aar形式放入Unity 把SDK编译成aar,然后把aar文件、manifest文件放入Unity工程的Assets/Plugins/Android目录下,以及libs下,没有的文件夹就自己新建. SDK的aar包也可以放入Assets/Plugins/Android目录中 其中一…...
【HDFS入门】深入解析DistCp:Hadoop分布式拷贝工具的原理与实践
目录 1 DistCp概述与应用场景 2 DistCp架构设计解析 2.1 系统架构图 2.2 执行流程图 3 DistCp核心技术原理 3.1 并行拷贝机制 3.2 断点续传实现原理 4 DistCp实战指南 4.1 常用命令示例 4.2 性能优化策略 5 异常处理与监控 5.1 常见错误处理流程 5.2 监控指标建议…...
电力MOSFET漏源过电压与窄脉冲自保护驱动电路
1 电力MOSFET的漏源过电压 2 窄脉冲自保护驱动电路说明 3 脉冲变压器设计说明 1 电力MOSFET的漏源过电压 如果器件接有感性负载,则当器件关断时,漏极电流的突变(di/dt)会产生比外部电源高的多的漏极尖峰电压,导致器件的击穿。电力MOSFET关断得越快,产生的过电压越高…...
【scikit-learn基础】--『监督学习』之 均值聚类
聚类算法属于无监督学习,其中最常见的是均值聚类,scikit-learn中,有两种常用的均值聚类算法: 一种是有名的K-means(也就是K-均值)聚类算法,这个算法几乎是学习聚类必会提到的算法; 另一个是均值偏移聚类,它与K-means各有千秋,只是针对的应用场景不太一样,但是知名度…...
Android 15强制edge-to-edge全面屏体验
一、背景 Edge-to-edge 全面屏体验并非 Android 15 才有的新功能,早在 Android 15 之前系统就已支持。然而,该功能推出多年来,众多应用程序依旧未针对全面屏体验进行适配。因此,在 Android 15 的更新中,Google 终于决…...
广州可信数据空间上线:1个城市枢纽+N个产业专区+高质量数据集(附28个数据集清单)
广州数据要素市场今日迎来历史性突破!全国首个城市可信数据空间正式上线,首批28个高质量数据集同步出台,覆盖生物医药、智能装备、绿色低碳等12大产业领域,激活37个高价值场景。 一、广州城市可信数据空间:1个城市枢纽…...
AgentGPT开源程序可以在浏览器中组装、配置和部署自主人工智能代理
一、软件介绍 文末提供程序和源码下载学习 AgentGPT开源程序可以允许您配置和部署自主 AI 代理。命名您自己的定制 AI 并让它开始实现任何可想象的目标。它将通过思考要执行的任务、执行它们并从结果中学习来尝试达到目标。 二、开始使用 AgentGPT 入门最简单的方式是使用项目…...
前端笔记-Axios
Axios学习目标 Axios与API交互1、Axios配置与使用2、请求/响应拦截器3、API设计模式(了解RESTful风格即可) 学习参考:起步 | Axios中文文档 | Axios中文网 什么是Axios Axios 是一个基于 Promise 的现代化 HTTP 客户端库,专…...
【EasyPan】MySQL主键与索引核心作用解析
【EasyPan】项目常见问题解答(自用&持续更新中…)汇总版 MySQL主键与索引核心作用解析 一、主键(PRIMARY KEY)核心作用 1. 数据唯一标识 -- 创建表时定义主键 CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,use…...
基于RK3588+FPGA+AI YOLO的无人船目标检测系统(一)概述
无人船在海洋监测、资源勘测、海上安全和科学研究等领域扮演着关键角色, 提升了海上任务的执行效率和安全性。在这一过程中,环境感知技术和目标检测 技术相辅相成,共同构建了系统的核心功能。随着人工智能行业的迅速发展,各 种…...
无人船 | 图解基于PID控制的路径跟踪算法(以全驱动无人艇WAMV为例)
目录 1 PID控制基本原理2 基于全驱动运动学的PID控制3 跟踪效果分析 1 PID控制基本原理 PID控制是一种常用的经典控制算法,其应用背景广泛,例如 工业自动化控制:温度控制、压力控制、流量控制、液位控制等过程控制系统多采用PID闭环&#x…...
为什么RPN经过的候选框处理后,要使用rcnn来进行候选框的分类和回归操作?
一句大白话总结:RPN是广撒网捕鱼,RCNN是细化鱼的分类和具体尺寸 在目标检测任务中,RPN(区域提议网络) 生成的候选框需要经过 RCNN(如 Fast R-CNN、Faster R-CNN) 进行分类和回归,这…...
代码实战保险花销预测
文章目录 摘要项目地址实战代码(初级版)实战代码(进阶版) 摘要 本文介绍了一个完整的机器学习流程项目,重点涵盖了多元线性回归的建模与评估方法。项目详细讲解了特征工程中的多项实用技巧,包括࿱…...
8.1 线性变换的思想
一、线性变换的概念 当一个矩阵 A A A 乘一个向量 v \boldsymbol v v 时,它将 v \boldsymbol v v “变换” 成另一个向量 A v A\boldsymbol v Av. 输入 v \boldsymbol v v,输出 T ( v ) A v T(\boldsymbol v)A\boldsymbol v T(v)Av. 变换 T T T…...
PythonWeb
参考:如何安装 Django |Django 文档 |姜戈 一、框架搭建 1、安装Django框架 pip3 install django 2、查看是否安装成功 pip3 show django 这样显示就是成功了 3、初始化项目 你想在哪个路径就 cd到哪个路径下输入一下命令就可以 django-admin startproject my…...
【大模型ChatGPT +DeepSeeK+python】最新AI赋能Python长时序植被遥感动态分析、物候提取、时空变异归因及RSEI生态评估
在遥感技术与人工智能深度融合的2025年,AI大模型正重塑长时序植被遥感数据分析范式。从Landsat/Sentinel卫星数据的智能化去云处理,到MODIS植被产品的AI辅助质量控制,以ChatGPT 、DeepSeeK为代表的大模型技术已成为提升遥感数据处理效率与精度…...
精益数据分析(11/126):辨别虚荣指标,挖掘数据真价值
精益数据分析(11/126):辨别虚荣指标,挖掘数据真价值 大家好!在创业和数据分析的学习道路上,我一直希望能和大家携手前行、共同进步。今天,咱们接着深入研读《精益数据分析》,这次聚…...
Time to event :Kaplan-Meier曲线、Log Rank检验与Shiny R
代码: # 创建数据框 data_a <- data.frame( usubjid = c(1- 1, 1- 2, 1- 3, 1- 4, 1- 5, 1- 6, 1- 7, 1- 8, 1- 9, 1-10, 2- 1, 2- 2, 2- 3, 2- 4, 2- 5, 2- 6, 2- 7, 2- 8, 2- 9, 2-10), cnsr = c(0,1,0,1,0,1,0,0,0,1,…...