Flask URL规则与变量 #

一、URL规则概述 #

1.1 URL规则语法 #

Flask的URL规则支持静态路径和动态变量:

python
# 静态URL
@app.route('/about')

# 动态URL(变量)
@app.route('/user/<username>')

# 带类型转换的动态URL
@app.route('/post/<int:id>')

1.2 规则组成 #

组成部分 说明 示例
静态部分 固定的URL路径 /user/
动态部分 可变的URL变量 <username>
类型转换器 指定变量类型 int:

二、动态变量 #

2.1 基本变量 #

python
@app.route('/user/<username>')
def show_user(username):
    return f'用户: {username}'

# 访问 /user/zhangsan → 用户: zhangsan
# 访问 /user/lisi → 用户: lisi

2.2 多个变量 #

python
@app.route('/user/<username>/post/<int:post_id>')
def show_post(username, post_id):
    return f'用户 {username} 的文章 {post_id}'

# 访问 /user/zhangsan/post/1 → 用户 zhangsan 的文章 1

2.3 变量命名规则 #

python
# 有效的变量名
@app.route('/user/<username>')      # 正确
@app.route('/user/<user_name>')     # 正确
@app.route('/user/<userName>')      # 正确

# 无效的变量名
# @app.route('/user/<user-name>')  # 错误:不能包含连字符
# @app.route('/user/<123user>')    # 错误:不能以数字开头

三、内置类型转换器 #

3.1 string转换器 #

python
# string是默认转换器,接受不包含斜杠的字符串
@app.route('/user/<string:username>')
def show_user(username):
    return f'用户: {username}'

# 等价于
@app.route('/user/<username>')
def show_user(username):
    return f'用户: {username}'

# 匹配示例
# /user/zhangsan → 正常
# /user/zhang-san → 正常
# /user/zhang/san → 404(包含斜杠)

3.2 int转换器 #

python
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'文章ID: {post_id}'

# post_id 自动转换为整数类型
# 匹配示例
# /post/1 → 正常,post_id = 1
# /post/123 → 正常,post_id = 123
# /post/abc → 404(不是整数)
# /post/-1 → 404(只接受正整数)

3.3 float转换器 #

python
@app.route('/price/<float:amount>')
def show_price(amount):
    return f'价格: ¥{amount:.2f}'

# amount 自动转换为浮点数
# 匹配示例
# /price/99.99 → 正常,amount = 99.99
# /price/100 → 正常,amount = 100.0
# /price/abc → 404(不是浮点数)

3.4 path转换器 #

python
@app.route('/file/<path:filename>')
def download(filename):
    return f'下载文件: {filename}'

# path可以包含斜杠
# 匹配示例
# /file/docs/readme.txt → filename = docs/readme.txt
# /file/static/css/style.css → filename = static/css/style.css
# /file/a/b/c/d.txt → filename = a/b/c/d.txt

3.5 uuid转换器 #

python
import uuid

@app.route('/item/<uuid:item_id>')
def show_item(item_id):
    return f'项目ID: {item_id}'

# item_id 自动转换为UUID对象
# 匹配示例
# /item/123e4567-e89b-12d3-a456-426614174000 → 正常
# /item/abc → 404(不是有效的UUID)

3.6 转换器对比 #

转换器 类型 匹配规则 示例
string str 不含斜杠的任意字符串 hello
int int 正整数 123
float float 正浮点数 99.99
path str 含斜杠的任意字符串 a/b/c
uuid UUID UUID格式字符串 123e4567-…

四、自定义转换器 #

4.1 创建自定义转换器 #

python
from werkzeug.routing import BaseConverter

class MobileConverter(BaseConverter):
    """手机号转换器"""
    
    def to_python(self, value):
        # 验证手机号格式
        if not value.isdigit() or len(value) != 11:
            raise ValueError('无效的手机号')
        return value
    
    def to_url(self, value):
        # 生成URL时调用
        return str(value)

# 注册转换器
app.url_map.converters['mobile'] = MobileConverter

# 使用自定义转换器
@app.route('/user/mobile/<mobile:phone>')
def user_by_phone(phone):
    return f'手机号: {phone}'

4.2 列表转换器 #

python
class ListConverter(BaseConverter):
    """列表转换器:将逗号分隔的字符串转为列表"""
    
    def to_python(self, value):
        return value.split(',')
    
    def to_url(self, values):
        return ','.join(str(v) for v in values)

app.url_map.converters['list'] = ListConverter

@app.route('/tags/<list:tags>')
def show_tags(tags):
    return f'标签: {tags}'

# 访问 /tags/python,flask,web
# tags = ['python', 'flask', 'web']

# 使用url_for生成URL
url_for('show_tags', tags=['python', 'flask'])
# 输出: /tags/python,flask

4.3 正则转换器 #

python
import re

class RegexConverter(BaseConverter):
    """正则表达式转换器"""
    
    def __init__(self, url_map, *items):
        super().__init__(url_map)
        self.regex = items[0]

app.url_map.converters['regex'] = RegexConverter

# 匹配4位数字
@app.route('/year/<regex("[0-9]{4}"):year>')
def show_year(year):
    return f'年份: {year}'

# 匹配邮箱
@app.route('/email/<regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"):email>')
def show_email(email):
    return f'邮箱: {email}'

4.4 枚举转换器 #

python
class EnumConverter(BaseConverter):
    """枚举转换器:只接受预定义的值"""
    
    def __init__(self, url_map, *items):
        super().__init__(url_map)
        self.items = items
        self.regex = '|'.join(items)
    
    def to_python(self, value):
        if value not in self.items:
            raise ValueError(f'无效的值: {value}')
        return value

app.url_map.converters['enum'] = EnumConverter

@app.route('/status/<enum("active","inactive","pending"):status>')
def show_status(status):
    return f'状态: {status}'

# 只匹配 active, inactive, pending

五、URL规则高级用法 #

5.1 可选变量 #

python
# Flask不直接支持可选变量,但可以定义多个路由
@app.route('/user')
@app.route('/user/<username>')
def show_user(username=None):
    if username:
        return f'用户: {username}'
    return '所有用户'

# /user → 所有用户
# /user/zhangsan → 用户: zhangsan

5.2 默认值 #

python
@app.route('/page')
@app.route('/page/<int:page_num>')
def show_page(page_num=1):
    return f'第 {page_num} 页'

# /page → 第 1 页
# /page/2 → 第 2 页

5.3 复杂URL规则 #

python
# 文件路径
@app.route('/static/<path:filepath>')
def serve_static(filepath):
    return f'静态文件: {filepath}'

# API版本
@app.route('/api/v<int:version>/users')
def api_users(version):
    return f'API v{version} 用户列表'

# 多层级路径
@app.route('/category/<category>/subcategory/<subcategory>/item/<int:item_id>')
def show_item(category, subcategory, item_id):
    return f'{category}/{subcategory}/{item_id}'

5.4 URL规则中的斜杠 #

python
# 严格匹配
@app.route('/about')
def about():
    return '关于'
# /about → 正常
# /about/ → 404

# 自动重定向
@app.route('/about/')
def about():
    return '关于'
# /about → 重定向到 /about/
# /about/ → 正常

六、URL构建 #

6.1 url_for函数 #

python
from flask import url_for

@app.route('/user/<username>')
def profile(username):
    return f'用户: {username}'

with app.test_request_context():
    # 基本用法
    print(url_for('profile', username='zhangsan'))
    # 输出: /user/zhangsan
    
    # 添加查询参数
    print(url_for('profile', username='zhangsan', page=1))
    # 输出: /user/zhangsan?page=1
    
    # 添加锚点
    print(url_for('profile', username='zhangsan', _anchor='comments'))
    # 输出: /user/zhangsan#comments
    
    # 外部URL
    print(url_for('profile', username='zhangsan', _external=True))
    # 输出: http://localhost:5000/user/zhangsan

6.2 蓝图中的url_for #

python
from flask import Blueprint, url_for

auth = Blueprint('auth', __name__, url_prefix='/auth')

@auth.route('/login')
def login():
    return '登录'

# 使用蓝图名作为前缀
url_for('auth.login')  # /auth/login
url_for('auth.login', next='/dashboard')  # /auth/login?next=/dashboard

6.3 静态文件URL #

python
# 静态文件URL
url_for('static', filename='css/style.css')
# 输出: /static/css/style.css

url_for('static', filename='js/main.js')
# 输出: /static/js/main.js

七、URL规则调试 #

7.1 查看所有规则 #

python
# 打印所有URL规则
for rule in app.url_map.iter_rules():
    print(f'规则: {rule.rule}')
    print(f'端点: {rule.endpoint}')
    print(f'方法: {rule.methods}')
    print(f'参数: {rule.arguments}')
    print('---')

7.2 匹配测试 #

python
from werkzeug.routing import Rule

# 测试URL是否匹配
with app.test_request_context():
    adapter = app.url_map.bind('')
    
    # 匹配URL
    endpoint, args = adapter.match('/user/zhangsan')
    print(f'端点: {endpoint}')  # profile
    print(f'参数: {args}')      # {'username': 'zhangsan'}

7.3 路由冲突检测 #

python
def check_route_conflicts():
    rules = {}
    conflicts = []
    
    for rule in app.url_map.iter_rules():
        key = (rule.rule, frozenset(rule.methods - {'HEAD', 'OPTIONS'}))
        if key in rules:
            conflicts.append({
                'rule': rule.rule,
                'endpoints': [rules[key], rule.endpoint]
            })
        else:
            rules[key] = rule.endpoint
    
    return conflicts

八、最佳实践 #

8.1 URL设计原则 #

python
# RESTful风格
@app.route('/users')              # 获取用户列表
@app.route('/users/<int:id>')     # 获取单个用户
@app.route('/users', methods=['POST'])  # 创建用户

# 资源嵌套
@app.route('/users/<int:user_id>/posts')  # 用户的文章列表
@app.route('/users/<int:user_id>/posts/<int:post_id>')  # 用户的单篇文章

# 避免过深的嵌套(建议不超过2层)
# 不推荐
# /users/<int:user_id>/posts/<int:post_id>/comments/<int:comment_id>

# 推荐
# /posts/<int:post_id>/comments/<int:comment_id>

8.2 类型选择 #

场景 推荐类型 示例
用户名 string /user/<username>
ID int /post/<int:id>
价格 float /price/<float:amount>
文件路径 path /file/<path:filename>
唯一标识 uuid /item/<uuid:id>

8.3 命名规范 #

python
# 推荐:有意义的变量名
@app.route('/user/<username>')
@app.route('/post/<int:post_id>')
@app.route('/category/<category_name>')

# 不推荐:无意义的变量名
@app.route('/user/<x>')
@app.route('/post/<int:id1>')

九、总结 #

9.1 核心要点 #

要点 说明
动态变量 使用<name>语法
类型转换 string、int、float、path、uuid
自定义转换器 继承BaseConverter
URL构建 使用url_for函数
匹配规则 按顺序匹配,静态优先

9.2 下一步 #

现在你已经掌握了URL规则与变量,接下来让我们学习 HTTP方法,了解如何处理不同的HTTP请求!

最后更新:2026-03-28