Flask生态(二):Flask-Login、Flask-Migrate、Flask-WTF、Flask-Mail

发布时间:2026/10/27 22:06:03

Flask生态(二):Flask-Login、Flask-Migrate、Flask-WTF、Flask-Mail 前文Flask生态一Flask-RESTful、Flask-Admin、Flask-SocketIO、Flask-SQLAlchemy、Flask-MonitoringDashboard的后续继续介绍几款围绕着Flask的开源项目。Flask-Login开源GitHub3.7K Star809 Fork官方文档。功能定位用户会话管理登录/登出/记住我。原理通过Flask的Session机制存储用户ID利用login_user()和logout_user()管理登录状态login_required装饰器保护需要登录的路由Session保护机制通过IPUser-Agent生成标识符检测会话劫持支持basic标记非新鲜和strong删除会话两种模式记住我功能通过持久化Cookie Token实现优势极简API与数据库无关可配合任何用户模型劣势只处理登录/未登录状态不处理权限管理需配合Flask-Principal或自建权限系统实战基于pip安装pip install Flask-Login入门示例importflaskimportflask_login appflask.Flask(__name__)app.secret_keysuper secret stringlogin_managerflask_login.LoginManager()login_manager.init_app(app)classUser(flask_login.UserMixin):def__init__(self,email,password):self.idemail self.passwordpassword users{leafstorm:User(leafstorm,secret)}login_manager.user_loaderdefuser_loader(id):returnusers.get(id)app.get(/login)deflogin():returnform methodpost Email: input nameemailbr Password: input namepassword typepasswordbr buttonLog In/button /formapp.post(/login)deflogin():userusers.get(flask.request.form[email])ifuserisNoneoruser.password!flask.request.form[password]:returnflask.redirect(flask.url_for(login))flask_login.login_user(user)returnflask.redirect(flask.url_for(protected))app.route(/protected)flask_login.login_requireddefprotected():returnflask.render_template_string(Logged in as: {{ user.id }},userflask_login.current_user)app.route(/logout)deflogout():flask_login.logout_user()returnLogged outFlask-Migrate开源GitHub2.4K Star235 Fork项目基于Alembic的数据库迁移管理与Flask-SQLAlchemy配合使用官方文档。原理封装Alembic的迁移引擎通过flask db init、flask db migrate、flask db upgrade等命令管理数据库Schema变更。Alembic会自动检测模型与数据库的差异生成迁移脚本。迁移三步步骤命令作用对标Django初始化flask db init创建migrations/目录类似于.git仅执行一次—生成flask db migrate -m 描述检测模型变化生成迁移脚本makemigrations执行flask db upgrade将迁移脚本应用到数据库migrateFlask-Migrate和Alembic的主要区别在于集成和使用方式Alembic独立工具可用于任何Python项目提供更底层的数据库迁移功能允许用户直接编写SQL迁移脚本。Flask-Migrate为Flask应用提供更高级别的接口自动检测模型更改并生成相应的迁移脚本这使得在Flask应用中进行数据库迁移更加简单和自动化。优势与Flask-SQLAlchemy、Flask CLI深度集成自动化程度高劣势迁移脚本的自动生成在复杂场景下可能不准确需手动调整实战基于pip安装pip install Flask-Migrate设置Alembic环境在项目中创建Alembic配置文件通常命名为alembic.ini包含数据库URL和其他配置选项。配置文件则可参考官方提供的Mako模版选择模板时根据是否多库以及异步Flask应用来判断。入门示例fromflaskimportFlaskfromflask_sqlalchemyimportSQLAlchemyfromflask_migrateimportMigrate appFlask(__name__)app.config[SQLALCHEMY_DATABASE_URI]sqlite:///app.dbdbSQLAlchemy(app)migrateMigrate(app,db)classUser(db.Model):iddb.Column(db.Integer,primary_keyTrue)namedb.Column(db.String(128))然后执行上述三条命令。其他命令行示例# 查看当前数据库处于哪个版本flask db current# 查看所有迁移历史flask dbhistory# 回滚迁移flask db downgrade# 合并迁移flask db merge flask db merge 002_add_column1 003_drop_column 004_add_column2注意解读私有化部署等多种场景下应用会累积有多个连续的迁移脚本可使用合并迁移功能将它们合并成一个。有助于简化迁移历史减少迁移脚本的数量使数据库迁移过程更加清晰。注意得是连续产生的脚本。不是所有操作都能自动回滚生产环境回滚前务必备份数据。Flask-WTF开源GitHub1.5K Star316 ForkFlask扩展集成WTForms用于简化Web表单的处理。可轻松定义表单、验证用户输入、给出清晰已读错误提示并内置CSRF跨站请求伪造保护使Flask应用更安全、更易维护。提供直观API让表单编程变得简单高效。官方文档。基于WTForms为Flask封装提供表单类定义字段校验规则集中管理自动CSRF保护模板中渲染字段和错误信息form.validate_on_submit()统一处理GET/POST判断与校验常用字段类型字段类HTML标签说明StringFieldinput typetext单行文本PasswordFieldinput typepassword密码输入框EmailFieldinput typeemail邮箱输入框TextAreaFieldtextarea多行文本BooleanFieldinput typecheckbox复选框SelectFieldselect下拉选择常用验证器验证器作用DataRequired()字段不能为空Length(min, max)字符长度限制Email()邮箱格式校验EqualTo(field_name)与另一个字段值一致Optional()允许字段为空跳过后续验证器对比项手动request.formFlask-WTF代码行数每个字段重复取/验/报三步表单类定义一次CSRF保护需手动实现自动自定义验证手动if/elsevalidate_xxx方法错误展示手动拼接form.field.errors自动收集适用场景简单表单如搜索框复杂表单注册、登录、资料编辑实战基于pip安装pip install Flask-WTF在app.py中配置SECRET_KEYCSRF Token依赖此密钥app.config[SECRET_KEY]your-secret-key# 生产环境用环境变量app.config[WTF_CSRF_ENABLED]True# 默认开启定义表单类# app/forms.pyfromflask_wtfimportFlaskFormfromwtformsimportStringField,PasswordField,EmailField,BooleanFieldfromwtforms.validatorsimportDataRequired,Length,Email,EqualTo,ValidationErrorfromapp.modelsimportUserclassRegisterForm(FlaskForm):注册表单usernameStringField(用户名,validators[DataRequired(message用户名不能为空),Length(min3,max50,message用户名长度 3-50 个字符)])emailEmailField(邮箱,validators[DataRequired(message邮箱不能为空),Email(message请输入有效的邮箱地址)])passwordPasswordField(密码,validators[DataRequired(message密码不能为空),Length(min6,message密码至少 6 位)])confirm_passwordPasswordField(确认密码,validators[DataRequired(message请再次输入密码),EqualTo(password,message两次输入的密码不一致)])# 自定义验证器检查用户名是否已被注册defvalidate_username(self,field):ifUser.query.filter_by(usernamefield.data).first():raiseValidationError(该用户名已被使用。)defvalidate_email(self,field):ifUser.query.filter_by(emailfield.data).first():raiseValidationError(该邮箱已被注册。)classLoginForm(FlaskForm):登录表单usernameStringField(用户名,validators[DataRequired(message用户名不能为空)])passwordPasswordField(密码,validators[DataRequired(message密码不能为空)])rememberBooleanField(记住我)在视图中使用表单# 文件路径app/blueprints/auth.py重构后的 register 和 loginfromflaskimportBlueprint,render_template,redirect,url_for,flashfromflask_loginimportlogin_user,logout_user,login_required,current_userfromapp.formsimportRegisterForm,LoginFormfromapp.modelsimportUser,db auth_bpBlueprint(auth,__name__)auth_bp.route(/register,methods[GET,POST])defregister():ifcurrent_user.is_authenticated:returnredirect(url_for(main.index))formRegisterForm()# form.validate_on_submit() 在 POST 请求时校验表单# GET 请求或校验失败时返回 Falseifform.validate_on_submit():userUser(usernameform.username.data,emailform.email.data)user.set_password(form.password.data)db.session.add(user)db.session.commit()login_user(user)flash(f注册成功欢迎你{user.username},success)returnredirect(url_for(main.index))# GET请求或校验失败时渲染带表单的模板returnrender_template(register.html,formform)auth_bp.route(/login,methods[GET,POST])deflogin():ifcurrent_user.is_authenticated:returnredirect(url_for(main.index))formLoginForm()ifform.validate_on_submit():userUser.query.filter_by(usernameform.username.data).first()ifuserisNoneornotuser.check_password(form.password.data):flash(用户名或密码错误。,error)returnrender_template(login.html,formform)login_user(user,rememberform.remember.data)flash(f欢迎回来{user.username},success)next_pagerequest.args.get(next)returnredirect(next_pageorurl_for(main.index))returnrender_template(login.html,formform)模板中渲染表单!-- 文件路径app/templates/register.html --{% extends base.html %} {% block title %}注册 - RUNOOB 博客{% endblock %} {% block content %}divclassauth-formh2注册/h2formmethodpost!-- form.hidden_tag() 自动生成 CSRF Token 隐藏字段 --{{ form.hidden_tag() }}divclassform-group{{ form.username.label }} {{ form.username(classform-input) }} {% if form.username.errors %} {% for error in form.username.errors %}spanclassfield-error{{ error }}/span{% endfor %} {% endif %}/divdivclassform-group{{ form.email.label }} {{ form.email(classform-input) }} {% for error in form.email.errors %}spanclassfield-error{{ error }}/span{% endfor %}/divdivclassform-group{{ form.password.label }} {{ form.password(classform-input) }} {% for error in form.password.errors %}spanclassfield-error{{ error }}/span{% endfor %}/divdivclassform-group{{ form.confirm_password.label }} {{ form.confirm_password(classform-input) }} {% for error in form.confirm_password.errors %}spanclassfield-error{{ error }}/span{% endfor %}/div{{ form.submit(classbtn-submit) }}/formpclassform-footer已有账号ahref{{ url_for(auth.login) }}立即登录/a/p/div{% endblock %}Flask-WTF的CSRF保护是自动的form.hidden_tag()会生成一个隐藏的input包含随机Token服务器在接受POST请求前验证此Token。任何外站提交的表单都因为没有正确Token而被拒绝。Flask-MailFlask的开源GitHub642 Star179 Fork官方扩展用于在Flask应用中发送电子邮件。封装SMTP和其他邮件发送协议简化邮件发送过程支持多种邮件后端。可轻松集成邮件功能到Web应用中如发送用户注册确认、密码重置或通知邮件。官方文档。功能附件发送使用msg.attach方法添加附件批量发送通过循环或使用邮件列表发送多封邮件使用模板结合Jinja2模板生成动态邮件内容自定义邮件后端支持Sendmail或其他后端。实战使用pip进行安装pip install Flask-Mail入门示例fromflaskimportFlaskfromflask_mailimportMail appFlask(__name__)# 配置SMTP服务器参数app.config[MAIL_SERVER]smtp.gmail.com# SMTP服务器地址app.config[MAIL_PORT]587# 端口Gmail使用587TLS或465SSLapp.config[MAIL_USE_TLS]True# 启用TLS加密更安全如果使用SSL设置MAIL_USE_SSLTrueapp.config[MAIL_USE_SSL]False# Gmail通常用TLS所以设为Falseapp.config[MAIL_USERNAME]admingmail.comapp.config[MAIL_PASSWORD]some-password# 邮箱密码或应用专用密码对于启用两步验证的服务app.config[MAIL_DEFAULT_SENDER]googlegmail.com# 默认发件人可选mailMail(app)注意对于Gmail等邮箱服务如果启用了两步验证不能直接使用普通密码需要生成应用专用密码。此外确保允许“安全性较低的应用程序访问”但出于安全考虑建议使用应用专用密码或OAuth。使用环境变量来存储敏感信息提高安全性importos app.config[MAIL_USERNAME]os.environ.get(MAIL_USERNAME)app.config[MAIL_PASSWORD]os.environ.get(MAIL_PASSWORD)发送普通邮件纯文本邮件适用于简单通知使用Message类创建邮件对象设置收件人、主题和内容。fromflask_mailimportMessage msgMessage(邮件主题,recipients[recipientexample.com])msg.body邮件内容使用Flask-Mail发送。mail.send(msg)HTML邮件允许发送带有格式、链接和图片的内容提供更好用户体验。支持同时发送纯文本和HTML版本确保兼容性。msgMessage(HTML邮件示例,recipients[recipientexample.com])msg.body这是纯文本版本用于不支持HTML的邮件客户端。msg.htmlh1Hello!/h1p这是一封strongHTML邮件/strong您可以添加样式和链接例如a hrefhttps://example.com访问网站/a。/pmail.send(msg)邮件发送可能失败原因包括网络问题、SMTP服务器错误或配置问题。为了提高应用的健壮性需要处理异常。使用try-except块捕获错误并采取相应措施。为了更健壮可考虑使用异步任务队列如Celery发送邮件避免阻塞Web请求或使用重试机制。发送带附件的邮件fromflask_mailimportMessageimportos msgMessage(带附件的邮件,recipients[recipientexample.com])msg.body请查收附件。# 添加附件withopen(path/to/file.pdf,rb)asf:msg.attach(file.pdf,application/pdf,f.read())mail.send(msg)推荐阅读Flask中文教程
延伸阅读

更多相关文章

2026/10/25 11:21:04

C语言赋值运算符详解:从=到==,零基础避坑指南

C语言里几乎每个程序都离不开这个符号。很多零基础同学第一次看到int a 10;,会下意识把读成“等于”。但从 C 语言的角度看,它更准确的名字是赋值运算符:把右边的值放进左边变量对应的内存单元里。这个区别如果一开始不搞清楚,后…

2026/10/24 8:22:46

阅文Android校招笔试卷深度拆解:考点分布与答题策略

"2023届阅文Android方向笔试卷"——看到这个标题,正在准备校招的安卓党估计第一反应就是:赶紧找真题看看考什么。我在Android这行做了不少年,也当过面试官、看过不少笔试答卷,说实话,阅文的这套卷子在互联网…

2026/10/27 22:01:38

Nmap网络扫描核心技术解析与实战应用

1. Nmap网络扫描技术全景解析 Nmap作为网络探测和安全审计领域的瑞士军刀,其核心价值在于通过主动探测技术揭示网络设备的真实状态。我第一次接触Nmap是在一次企业内网渗透测试中,当时用 nmap -sS -T4 192.168.1.0/24 这个简单的命令就发现了三台存在高…

2026/10/27 22:01:38

MySQL GROUP BY与COUNT高效统计状态数据详解

1. 项目概述 在日常数据库操作中,统计不同状态的数据记录数量是最基础也是最频繁的需求之一。作为一名长期与MySQL打交道的开发者,我发现很多新手在面对这类统计需求时,往往会写出效率低下甚至错误的SQL语句。今天我们就来深入探讨如何正确使…

2026/10/27 22:01:38

光纤传感器原理与类型:物性型vs结构型核心差异解析

简介:本资源是一份面向电子、测控、光电类专业学生及工程技术人员的光纤传感器基础原理图解资料,聚焦物性型与结构型两大分类及其核心工作机制,解决对光纤传感技术物理本质与典型应用理解不深的问题。文档以图文结合方式系统阐述温度、压力、…

2026/10/27 22:01:38

i2 Analyst‘s Notebook 8 实战指南:从话单导入到司法级图谱分析

简介:本资源是一份面向安全分析、金融风控及刑侦调查从业者的i2 Analysts Notebook 8专业培训教材,聚焦话单挖掘、银行交易追踪、案件串并与人员动态关系建模等实战场景,帮助初学者系统掌握IBM这款主流图谱分析工具的核心能力。文档为单文件W…

2026/10/27 22:01:38

数据库ANY权限的安全风险与最佳实践

1. 数据库权限管理中的"ANY权限"解析 在数据库安全管理领域,ANY权限(如GRANT SELECT ANY TABLE)是一种特殊类型的系统权限,它允许被授权者对数据库中所有对象(包括当前和未来创建的对象)执行特定…

2026/10/27 21:56:38

GraphQL批量查询攻击防护与优化实践

1. 当GraphQL批量查询成为攻击者的新武器 第一次在生产环境遇到GraphQL批量查询攻击时,我正盯着监控面板上突然飙升的CPU曲线发愣。那是一个看似平常的API请求,却在短短几秒内触发了数十个关联查询,导致数据库连接池瞬间耗尽。这种攻击不像传…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑