当前位置: 首页 > article >正文

Flask 路由装饰器:从 URL 到视图函数的优雅映射

前置知识,关于Python装饰器的语法,链接:Python 装饰器:从“语法糖”到“代码神器”的深度解析

1、路由装饰器的功能:给 URL 贴 “功能标签”

在 Flask 开发中,你一定见过这样的代码:

from flask import Flask  
app = Flask(__name__)  @app.route('/')  
def index():  return "Hello, Flask!"  

这里的 @app.route('/') 就是 Flask 的路由装饰器,它的核心功能是:将特定的 URL 与处理该 URL 的视图函数绑定。

简单来说,它告诉 Flask:“当用户访问 '/' 路径时,执行 index 函数并返回结果。”

通过这一“贴标签”操作,开发者无需手动维护复杂的 URL 映射表,只需用装饰器标记每个视图函数对应的路径,Flask 就能自动完成 URL 到视图函数的匹配。


2、路由装饰器的核心机制:从 @app.routeurl_map 的全流程

路由装饰器的底层实现依赖 Flask 的路由注册与匹配系统,核心流程分为 注册阶段请求处理阶段

2.1 注册阶段:@app.route 如何绑定 URL 与视图?

@app.route 本质是一个语法糖,其底层通过调用 app.add_url_rule() 完成路由规则的注册。

关键步骤:
  1. @app.route(rule, **options) 触发注册
    当用 @app.route('/') 装饰视图函数 index 时,Flask 会自动执行以下逻辑:

    app.add_url_rule(  rule='/',  # URL 路径(必填)  endpoint='index',  # 路由端点(默认使用视图函数名)  view_func=index,  # 绑定的视图函数(必填)  **options  # 其他参数(如 methods、strict_slashes 等)  
    )  
    
  2. 创建 Rule 对象并存储到 url_map
    add_url_rule 会生成一个 Rule 对象(包含 URL 路径、支持的 HTTP 方法、参数解析规则等关键信息),并将其添加到 app.url_map(Flask 应用的路由规则总仓库,负责管理所有注册的 Rule)中。

扩展:
如上代码,add_url_rule里有个参数是endpoint,叫做路由端点,默认使用视图函数名,这个信息保存到Rule对象里,在反向查找url_for,也就是根据endpoint找URL的时候有作用。
关于url_for及页面重定向的内容,请见这一篇:Flask中的路由跳转机制:url_for生成动态URL、redirect页面重定向

2.2 请求处理阶段:url_map 如何匹配 URL?

当用户发起请求(如访问 http://域名/),Flask 的处理流程如下:

关键步骤:
  1. 构建请求上下文:Flask 根据请求的 URL、方法等信息,生成 request 对象。

  2. url_map 匹配规则
    url_map 通过 match() 方法匹配请求的 URL,找到对应的 Rule 对象。匹配逻辑包括:

    • 静态路径直接匹配(如 /about 对应 Rule(rule='/about'))。
    • 动态参数解析(如 /user/alice 匹配 Rule(rule='/user/<username>'),提取 username='alice')。
  3. 触发视图函数执行
    匹配到 Rule 后,Flask 从 Rule 中获取绑定的 view_func(视图函数),并将解析出的参数(如 username)传递给视图函数执行,最终将返回值作为响应返回给用户。


3、路由装饰器的典型应用场景

3.1、基本路由:静态路径与视图绑定

为固定 URL 路径定义视图函数,访问对应路径返回固定内容:

@app.route('/about')  
def about():  return "关于我们"  @app.route('/contact')  
def contact():  return "联系我们"  

3.2、动态路由:捕获 URL 中的参数

通过 <参数> 语法捕获 URL 中的动态部分(如用户 ID、文章标题),常用于详情页或 API 接口。

支持参数默认值,使同一视图函数处理多种路径:

# 带默认值的动态路由(默认页为第1页)  
@app.route('/page', defaults={'page': 1})  
@app.route('/page/<int:page>')  
def show_page(page):  return f"第 {page} 页内容"  # 用户详情页(动态用户名)  
@app.route('/user/<username>')  
def user_profile(username):  return f"用户 {username} 的个人页面"  # API 接口(整数类型的文章 ID)  
@app.route('/api/post/<int:post_id>')  
def get_post(post_id):  data = db.query(Post).filter_by(id=post_id).first()  return jsonify(data.to_dict())  

3.3、支持多种 HTTP 方法

路由默认只支持 GET 请求。
如果需要处理其他方法,必须通过 methods 参数显式声明,如表单提交的 POST 请求,。

GET从服务器获取资源(如网页、数据),请求参数通过 URL 传递(如 ?username=alice)。
POST向服务器提交数据(如表单、文件),参数通过请求体(Body)传递,不会显示在 URL 中。

from flask import request  @app.route('/login', methods=['GET', 'POST'])  
def login():  if request.method == 'POST':  # 处理登录表单提交(用户名/密码验证)  return redirect(url_for('user_profile', username=username))  return render_template('login.html')  # GET 请求返回登录表单  

3.4、蓝图(Blueprints):按模块拆分大型项目路由

在大型 Flask 项目中,若所有路由都直接写在主应用文件(如 app.py)中,代码会变得臃肿且难以维护。

蓝图(Blueprints)是 Flask 提供的“模块化工具”,允许将路由按功能模块(如用户、商品、订单)拆分到不同文件中,实现代码的解耦与复用。


下面以具体示例来讲解,假设我们有一个电商项目,包含用户模块商品模块,可以通过蓝图将它们的路由分开管理:

步骤1:创建用户模块蓝图(user_bp)
user/views.py 文件中定义用户相关路由:

# user/views.py  
from flask import Blueprint, render_template, request  # 创建用户模块蓝图,路径前缀为 /user  
user_bp = Blueprint('user', __name__, url_prefix='/user')  @user_bp.route('/register', methods=['GET', 'POST'])  # 实际路径:/user/register  
def register():  if request.method == 'POST':  # 处理用户注册表单提交(数据库写入等逻辑)  return "注册成功"  return render_template('user/register.html')  # GET 请求返回注册页面  @user_bp.route('/login')  # 实际路径:/user/login  
def login():  return render_template('user/login.html')  # 用户登录页面  

步骤2:创建商品模块蓝图(product_bp)
product/views.py 文件中定义商品相关路由:

# product/views.py  
from flask import Blueprint, jsonify  
from models import Product  # 假设 Product 是数据库模型  # 创建商品模块蓝图,路径前缀为 /product  
product_bp = Blueprint('product', __name__, url_prefix='/product')  @product_bp.route('/list')  # 实际路径:/product/list  
def product_list():  # 查询数据库获取商品列表  products = Product.query.all()  return jsonify([p.to_dict() for p in products])  # 返回 JSON 格式的商品数据  @product_bp.route('/detail/<int:product_id>')  # 实际路径:/product/detail/123  
def product_detail(product_id):  # 根据 ID 查询商品详情  product = Product.query.get_or_404(product_id)  return jsonify(product.to_dict())  

步骤3:主应用注册蓝图
在主文件 app.py 中注册所有蓝图,将模块路由整合到应用中:

# app.py  
from flask import Flask  
from user.views import user_bp  # 导入用户模块蓝图  
from product.views import product_bp  # 导入商品模块蓝图  app = Flask(__name__)  # 注册用户模块蓝图(路径前缀 /user)  
app.register_blueprint(user_bp)  # 注册商品模块蓝图(路径前缀 /product)  
app.register_blueprint(product_bp)  if __name__ == '__main__':  app.run()  

4、进阶技巧:细粒度控制路由行为

4.1、自定义 URL 转换器

突破 Flask 内置参数类型(intstring 等)的限制,通过自定义转换器支持正则匹配、日期解析等复杂需求:

from werkzeug.routing import BaseConverter  class RegexConverter(BaseConverter):  def __init__(self, url_map, regex):  super().__init__(url_map)  self.regex = regex  # 接收正则表达式参数  # 注册自定义转换器(名称为 regex)  
app.url_map.converters['regex'] = RegexConverter  # 使用示例:匹配手机号格式(1开头+10位数字)  
@app.route('/phone/<regex("1[3-9]\\d{9}"):phone_num>')  
def validate_phone(phone_num):  return f"手机号:{phone_num}"  

4.2、子域名匹配

通过 subdomain 参数实现子域名与主域名的路由隔离(需配置 SERVER_NAME):

app.config['SERVER_NAME'] = 'example.com:5000'  # 配置域名和端口  @app.route('/', subdomain='blog')  # 匹配 blog.example.com:5000/  
def blog_index():  return "博客首页"  @app.route('/', subdomain='www')  # 匹配 www.example.com:5000/  
def www_index():  return "网站首页"  

5、注意事项:避开路由陷阱

5.1、URL 末尾斜杠规则

  • 带斜杠路径(如 /projects/):类似文件夹,访问 /projects 会自动重定向到 /projects/(避免 404)。
  • 无斜杠路径(如 /about):严格匹配,访问 /about/ 会返回 404(适合表示唯一资源,如文件)。

5.2、路由顺序影响匹配结果

Flask 按路由定义的顺序匹配 URL,更具体的路径应放在前面。例如:

# 正确顺序:先匹配 /user/me,再匹配通用的 /user/<username>  
@app.route('/user/me')  
def user_me():  return "当前用户"  @app.route('/user/<username>')  
def user_profile(username):  return f"用户 {username}"  # 错误顺序:/user/me 会被错误匹配为 username='me'  

5.3、性能:路由匹配效率

Flask 使用 Werkzeug 的 Map 进行路由匹配,性能足够应对大多数场景。优化建议:

  • 高频访问的路由(如首页)放在前面。
  • 避免使用复杂的正则表达式参数(可能降低匹配效率)。

相关文章:

Flask 路由装饰器:从 URL 到视图函数的优雅映射

前置知识&#xff0c;关于Python装饰器的语法&#xff0c;链接&#xff1a;Python 装饰器&#xff1a;从“语法糖”到“代码神器”的深度解析 1、路由装饰器的功能&#xff1a;给 URL 贴 “功能标签” 在 Flask 开发中&#xff0c;你一定见过这样的代码&#xff1a; from fla…...

DDoS防护实战——从基础配置到高防IP部署

一、基础防护&#xff1a;服务器与网络层加固 Linux内核优化&#xff1a; 调整TCP协议栈参数&#xff0c;缓解SYN Flood攻击&#xff1a; # 启用SYN Cookie并减少超时时间 echo 1 > /proc/sys/net/ipv4/tcp_syncookies echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout…...

aws平台s3存储桶夸域问题处理

当我们收到开发反馈s3存在跨域问题 解决步骤&#xff1a; 配置 S3 存储桶的 CORS 设置&#xff1a; 登录到 AWS 管理控制台。转到 S3 服务。选择你存储文件的 存储桶。点击 权限 标签页。在 跨域资源共享&#xff08;CORS&#xff09;配置 部分&#xff0c;点击 编辑。 登陆…...

HOT100(二叉树)

二叉树 二叉树的中序遍历 class Solution { public:void traversal(TreeNode* root, vector<int> & vec){if(root nullptr) return;traversal(root->left, vec);vec.push_back(root->val);traversal(root->right, vec);}vector<int> inorderTraver…...

【vue-text-highlight】在vue2的使用教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、下载二、使用步骤1.引入库2.用法 效果速通 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发…...

pycharm无法正常调试问题

pycharm无法正常调试问题 1.错误代码 已连接到 pydev 调试器(内部版本号 231.8109.197)Traceback (most recent call last):File "E:\Python\pycharm\PyCharm 2023.1\plugins\python\helpers\pydev\_pydevd_bundle\pydevd_comm.py", line 304, in _on_runr r.deco…...

springboot3.4.5-springsecurity+session

创建springboot项目&#xff0c;添加以下依赖&#xff1a; LombokSpring WebSpring SecuritySpring Data JDBCMyBatis FrameworkMySQL Driver 添加fastjson2进行序列化和反序列化 <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>f…...

网络安全利器:蜜罐技术详解

蜜罐是网络安全领域中一种主动防御和情报收集的重要工具。本文将深入探讨蜜罐技术的原理、类型、应用场景以及部署注意事项。 1. 什么是蜜罐? 蜜罐(Honeypot)是一种安全资源,其价值在于被探测、攻击或未经授权使用。简单来说,蜜罐就是一个诱饵系统,用来吸引黑客的注意力…...

Leetcode百题斩-哈希

看来面试前还是要老老实实刷leetcode为好&#xff0c;今天看到一个题库&#xff0c;leetcode百题斩&#xff0c;刚好最近面试的这两题全在里面。瞄了一眼&#xff0c;也有不少题之前居然也刷过。那么&#xff0c;冲冲冲&#xff0c;看多久能把这百题刷完。 第一天&#xff0c;先…...

MySQL替换瀚高数据库报错: TO_DAYS()不存在(APP)

文章目录 环境症状问题原因解决方案报错编码 环境 系统平台&#xff1a;中标麒麟&#xff08;海光&#xff09;7,中标麒麟&#xff08;飞腾&#xff09;7 版本&#xff1a;4.5 症状 MySQL替换为瀚高数据库进行应用系统适配报错&#xff1a;TO_DAYS&#xff08;&#xff09;不…...

EXIST与JOIN连表比较

结论 1&#xff1a;EXIST可以用于链表&#xff0c;且可以利用到索引2&#xff1a;当join无法合理利用到索引&#xff0c;可以尝试EXIST链表3&#xff1a;EXIST在某些情况下可以更好地利用到索引4&#xff1a;大数据量时&#xff0c;要考虑EXIST的使用 EXIST SQL: EXPLAN JOIN…...

【Linux】利用多路转接epoll机制、ET模式,基于Reactor设计模式实现

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;多路转接epoll&#xff0c;实现echoserver 至此&#xff0c;Linux与…...

【jvm第7集】jvm调优工具(命令行工具)

文章目录 JVM 调优工具&#xff08;命令行工具&#xff09;jps&#xff08;Java Virtual Machine Process Status Tool&#xff09;jstat&#xff08;JVM Statistics Monitoring Tool&#xff09;jmap&#xff08;Memory Map Tool&#xff09;jstack&#xff08;Thread Stack T…...

react中运行 npm run dev 报错,提示vite.config.js出现错误 @esbuild/win32-x64

在React项目中运行npm run dev时&#xff0c;如果遇到vite.config.js报错&#xff0c;提示esbuild/win32-x64在另一个平台中被使用&#xff0c;通常是由于依赖冲突或缓存问题导致的。解决方法是删除node_modules文件夹&#xff0c;并重新安装依赖。 如下图&#xff1a; 解决办…...

鸿蒙UI开发——Builder与LocalBuilder对比

1、概 述 在ArkUI中&#xff0c;有的朋友应该接触过Builder和LocalBuilder。其中有了LocalBuilder的存在&#xff0c;是为了解决组件的父子关系和状态管理的父子关系保持一致的问题。 这里面最直观的表现则是this的指向问题与组件刷新问题&#xff0c;本文对Builder与LocalBu…...

关于光谱相机的灵敏度

一、‌灵敏度的核心定义‌ ‌光谱灵敏度&#xff08;单色灵敏度&#xff09;‌ 描述光谱相机对单色辐射光的响应能力&#xff0c;即探测器对特定波长入射光的输出信号强度与入射光功率的比值。 例如&#xff0c;若在680nm波长下的光谱灵敏度较高&#xff0c;则表示该相机对此…...

Model 速通系列(一)nanoGPT

这个是新开的一个系列用来手把手复现一些模型工程&#xff0c;之所以开这个系列是因为有人留言说看到一个工程不知道从哪里读起&#xff0c;出于对自身能力的提升与兴趣&#xff0c;故新开了这个系列。由于主要动机是顺一遍代码并提供注释。 该系列第一篇博客是 nanoGPT &…...

微信小程序中,一个页面的数据改变了,怎么通知另一个页面也改变?

在微信小程序中&#xff0c;当一个页面的数据改变后通知另一个页面更新&#xff0c;可以通过以下步骤实现&#xff1a; 方法一&#xff1a;使用全局事件总线&#xff08;推荐&#xff09; 步骤说明&#xff1a; 在 app.js 中创建事件系统 在全局 App 实例中实现事件监听和触发…...

MySQL--day4--排序与分页

&#xff08;以下内容全部来自上述课程&#xff09; 1. 排序数据 1.1 排序基本使用 #1.排序 #如果没有使用排序操作&#xff0c;默认情况下查询返回的数据是按照添加数据的顺序显示的 SELECT * FROM employees;# 练习:按照salary从高到低的顺序显示员工信息 # 使用 ORDER …...

自动化测试脚本点击运行后,打开Chrome很久??

亲爱的小伙伴们大家好。 小编最近刚换了电脑&#xff0c;这几天做自动化测试发现打开Chrome浏览器需要等待好长时间&#xff0c;起初还以为代码有问题&#xff0c;或者Chromedriver与Chrome不匹配造成的&#xff0c;但排查后发现并不是&#xff01;&#xff01; 在driver.py中…...

iOS热更新技术要点与风险分析

iOS的热更新技术允许开发者在无需重新提交App Store审核的情况下&#xff0c;动态修复Bug或更新功能&#xff0c;但需注意苹果的审核政策限制。以下是iOS热更新的主要技术方案及要点&#xff1a; 一、主流热更新技术方案 JavaScript动态化框架 React Native & Weex 通过Jav…...

系统架构设计(十二):统一过程模型(RUP)

简介 RUP 是由 IBM Rational 公司提出的一种 面向对象的软件工程过程模型&#xff0c;以 UML 为建模语言&#xff0c;是一种 以用例为驱动、以架构为中心、迭代式、增量开发的过程模型。 三大特征 特征说明以用例为驱动&#xff08;Use Case Driven&#xff09;需求分析和测…...

系分论文《论软件系统安全分析和应用》

系统分析师论文范文系列 【摘要】 2023年3月&#xff0c;我司承接了某知名电商企业“智能化供应链管理系统”的开发任务&#xff0c;我作为系统分析师负责全面的安全分析与设计工作。该系统以提升电商供应链效率为核心&#xff0c;整合仓储、物流、支付等模块&#xff0c;并需应…...

Mac安装redis

1、 去往网址 http://​编download.​编redis.io/releases/ 找到任意 结尾为* .tar.gz的文件下载下来 2、使用终端进入下载下来的redis文件 3、直接执行redis-server 如果出现redis标志性的图代表成功 如果显示command not found :redis-server 则在终端再进入src文件夹下&…...

srs-7.0 支持obs推webrtc流

demo演示 官方教程: https://ossrs.net/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP 实现原理就是通过WHIP协议来传输 SDP信息 1、运行 ./objs/srs -c conf/rtc.conf 2、obs推流 3、web端播放webrtc流 打开web:ht...

Babylon.js学习之路《七、用户交互:鼠标点击、拖拽与射线检测》

文章目录 1. 引言&#xff1a;用户交互的核心作用1.1 材质与纹理的核心作用 2. 基础交互&#xff1a;鼠标与触摸事件2.1 绑定鼠标点击事件2.2 触摸事件适配 3. 射线检测&#xff08;Ray Casting&#xff09;3.1 射线检测的原理3.2 高级射线检测技巧 4. 拖拽物体的实现4.1 拖拽基…...

星际争霸小程序:用Java实现策略模式的星际大战

在游戏开发的世界里&#xff0c;策略模式是一种非常实用的设计模式&#xff0c;它允许我们在运行时动态地选择算法或行为。今天&#xff0c;我将带你走进一场星际争霸的奇幻之旅&#xff0c;用Java实现一个简单的星际争霸小程序&#xff0c;通过策略模式来模拟不同种族单位的战…...

请问交换机和路由器的区别?vlan 和 VPN 是什么?

交换机和路由器的区别 特性交换机&#xff08;Switch&#xff09;路由器&#xff08;Router&#xff09;工作层级数据链路层&#xff08;L2&#xff0c;基于MAC地址&#xff09;网络层&#xff08;L3&#xff0c;基于IP地址&#xff09;主要功能在局域网&#xff08;LAN&#…...

BERT 作为Transformer的Encoder 为什么采用可学习的位置编码

摘要 BERT 在位置编码上与原始 Transformer 论文中的 sin/cos 公式不同&#xff0c;选择了可学习&#xff08;learned&#xff09;的位置嵌入方案。本文将从 Transformer 原始位置编码选项入手&#xff0c;分析 BERT 选择 learned positional embeddings 的四大核心原因&#x…...

Python数据可视化高级实战之一——绘制GE矩阵图

目录 一、课程概述 二、GE矩阵? 三、GE 矩阵图的适用范围 五、GE 矩阵的评估方法 (一)市场吸引力的评估要素 二、企业竞争实力的评估要素 三、评估方法与实践应用 1. 定量与定性结合法 2. 数据来源 六、GE矩阵的图形化实现 七、总结:GE 矩阵与 BCG 矩阵的对比分析 (一)GE…...