flask_之URL
URL篇
在分析路由匹配过程之前,我们先来看看 flask
中,构建这个路由规则的两种方法:
-
通过
@app.route()
decorator -
通过
app.add_url_rule
,这个方法的签名为add_url_rule(self, rule, endpoint=None, view_func=None, **options)
,参数的含义如下:-
rule
: url 规则字符串,可以是静态的/path
,也可以包含/
-
endpoint
:要注册规则的 endpoint,默认是view_func
的名字 -
view_func
:对应 url 的处理函数,也被称为视图函数
-
这两种方法是等价的,也就是说:
1 2 3 | @app .route( '/' ) def hello(): return "hello, world!" |
也可以写成
1 2 3 4 | def hello(): return "hello, world!" app.add_url_rule( '/' , 'hello' , hello) |
其实,还有一种方法来构建路由规则——直接操作 app.url_map
这个数据结构。不过这种方法并不是很常用,因此就不展开了
静态路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | @app .route( '/' ) def hello_world(): # 变量可以通过赋值传到前端,前端可以通过Jinja语法{{}}渲染 return render_template( 't1.html' , name = 't1' , age = 16 ) @app .route( '/services' ) def services(): return 'Services' @app .route( '/about' ) def about(): return 'About' # 相对projects解释类似于文件夹解释形式,指向某一个文件夹下的某个文件 @app .route( '/projects/' ) @app .route( '/projects_our' ) # 可以定义多个URL到同一个视图函数上,Flask支持 def projects(): return 'Projects' @app .route( '/login' ,methods = [ "GET" , "POST" ]) def login(): return render_template( 'login.html' , req_method = request.method) |
动态路由
1 2 3 4 5 6 7 8 9 10 11 12 | # 动态路由 @app .route( '/user/<username>' ) def user(username): print username return username # 路由转换器:指定参数类型 # flask提供3种:int(整形)|float(浮点型)|path(路径,并支持一个/) @app .route( '/user/<int:user_id>' ) def user(user_id): print user_id return 'User_id:%s' % user_id |
自定义路由规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # flask不提供正则表达的形式的URL匹配 # 可通过定义完成 # 1、from werkzeug.routing import BaseConverter # 2、自定义类 #转换器 class RegexConverter(BaseConverter): def __init__( self ,url_map, * items): super (RegexConverter, self ).__init__( self ) # print items # (u'[a-z]{3}[A-Z]{3}',) # print url_map # URL 的一个MAP对象,类似路由表 self .regex = items[ 0 ] # 3、要将定义的类注册到APP的url_map中,定义名称 # app.url_map.converters['regex'] = RegexConverter # 4、使用 @app .route( '/user/<regex("[a-z]{3}[A-Z]{3}"):username>' ) def user(username): print username return 'Username:%s' % username |
浅析源码
注册路由规则的时候,flask 内部做了哪些东西呢?我们来看看 route
方法:

def route(self, rule, **options): """A decorator that is used to register a view function for a given URL rule. This does the same thing as :meth:`add_url_rule` but is intended for decorator usage. """ def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
route
方法内部也是调用 add_url_rule
,只不过在外面包了一层装饰器的逻辑,这也验证了上面两种方法等价的说法

def add_url_rule(self, rule, endpoint=None, view_func=None, **options): """Connects a URL rule. Works exactly like the :meth:`route` decorator. If a view_func is provided it will be registered with the endpoint. """ if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only ``GET`` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) if isinstance(methods, string_types): raise TypeError('Allowed methods have to be iterables of strings, ' 'for example: @app.route(..., methods=["POST"])') methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. provide_automatic_options = getattr(view_func, 'provide_automatic_options', None) if provide_automatic_options is None: if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS') else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError('View function mapping is overwriting an ' 'existing endpoint function: %s' % endpoint) self.view_functions[endpoint] = view_func
上面这段代码省略了处理 endpoint 和构建 methods 的部分逻辑,可以看到它主要做的事情就是更新 self.url_map
和 self.view_functions
两个变量。找到变量的定义,发现 url_map
是 werkzeug.routeing:Map
类的对象,rule
是 werkzeug.routing:Rule
类的对象,view_functions
就是一个字典。这和我们之前预想的并不一样,这里增加了 Rule
和 Map
的封装,还把 url
和 view_func
保存到了不同的地方。
需要注意的是:每个视图函数的 endpoint 必须是不同的,否则会报 AssertionError
。
未完待续。。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性