发布时间:2026/9/1 20:18:16
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/9/1 20:18:16

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

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

2026/9/1 20:18:16

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

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

2026/9/1 20:33:18

美团校招笔试复盘:从贪心到状态压缩的算法突破

1. 第2场笔试给我的整体印象:时间紧、样例弱、边界多1.1 试卷结构与时长带来的压迫感我参加的是美团2023校招技术岗的第2场在线笔试,整场下来最大的感受就是:题量不算夸张,但时间分配稍有不慎就会翻车。编程题部分通常是4道&#…

2026/9/1 20:33:18

技术博客创作必备:从项目资料到关键词布局的完整指南

当前为测试会话,未提供具体技术项目标题与可用的项目正文材料。无法生成“可直接发布的 CSDN 技术长文”。请按以下格式补充真实可用的项目资料:项目标题:例如“xxx 开源本地部署工具” 项目正文:可包含项目简介、功能列表、安装命…

2026/9/1 20:33:18

Odoo ERP在印刷行业文档管理中的落地实践与部署方案

这次我们来看一个实战向的话题:Odoo ERP 在印刷行业的文档管理。印刷企业的数字化转型里,文档管理往往比排产系统更早被提上日程,客户来稿、打样确认、工艺单、版材记录、质检报告、外发回单,这些文件如果继续放在共享盘里&#x…

2026/9/1 20:33:18

用一条河讲透Flink核心概念:流处理、窗口与状态

很多刚接触 Flink 的开发者,最大的障碍往往不是 API 本身,而是被一堆抽象术语劝退:无界流、有界流、窗口、水位线、状态后端、检查点、精确一次……每个词单独看都能理解,合在一起就不知道它们在系统里到底扮演什么角色。这篇文章…

2026/9/1 20:28:17

Python生成器与迭代器:高效处理大数据

Python生成器与迭代器:高效处理大数据 生成器和迭代器是Python处理大数据和流式数据的核心工具,能节省内存、提高效率。本篇将深入学习迭代器协议、生成器函数和生成器表达式。 一、迭代器(Iterator) 1. 什么是迭代器? 迭代器是实现了迭代器协议的对象,即包含 __iter__…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/1 8:27:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/1 7:04:43

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…