如何动态的设置route.path path

Python的Flask框架中@app.route的用法教程
作者:Ainsley
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Python的Flask框架中@app.route的用法教程,包括相关的正则表达式讲解,是Flask学习过程当中的基础知识,需要的朋友可以参考下
在我上一篇文章,我搭了一个框架,模拟了Flask网站上“@app.route(‘/')”第一条例子的行为。
如果你错过了那篇“这不是魔法”,请点击。
在这篇文章中,我们打算稍微调高点难度,为我们的URL加入可变参数的能力,在本文的最后,我们将支持下述代码段所期望达到的行为。
app = Flask(__name__)
@app.route("/hello/&username&")
def hello_user(username):
return "Hello {}!".format(username)
这样下面的路径实例(path):
/hello/ains
将会匹配上面的路径,给我们的输出为
Hello ains!
以正则的形式表达我们的路径。
现在我们将允许我们的URL动态变化,我们不再能够将用先前使用“@app.route()”注册的路径直接与路径实例比较。
我们将用什么替代?我们需要用上正则表达式,这样我们就可以将路径作为一种模式进行匹配,而不和一条固定的字符串比较了。
我不打算在本文展开讨论正则表达式的细节,不过如果你需要一份复习资料,可以点击这个。
那么,我们的第一步是将我们的路径转化成正则表达式模式,这样我们就能在输入路径实例时进行匹配。我们也将使用这个正则表达式提取我们感兴趣的变量。
那么,匹配路径”/hello/”的正则表达式该长啥样呢?
嗯一个简单的正则表达式譬如“^/hello/(.+)$”将是个好的开始,让我们一起看看它和代码是怎么一起工作的:
route_regex = re.compile(r"^/hello/(.+)$")
match = route_regex.match("/hello/ains")
print match.groups()
将会输出:
不错,不过,理想情况是我们想要维护我们已经匹配上的第一组链接,并且从路径“/hello/”识别出“username”。
命名捕获组
幸运的是,正则表达式也支持命名捕获组,允许我们给匹配组分配一个名字,我们能在读取我们的匹配之后找回它。
我们可以使用下述符号,给出第一个例子识别“username”的捕获组。
/hello/(&?P&username&.+)"
然后我们可以对我们的正则表达式使用groupdict()方法,将所有捕获组当作一个字典,组的名字对应匹配上的值。
那么我们给出下述代码:
route_regex = re.compile(r'^/hello/(?P&username&.+)$')
match = route_regex.match("/hello/ains")
print match.groupdict()
将为我们输出以下字典:
{'username': 'ains'}
现在,有了我们所需要的正则表达式的格式,以及如何使用它们去匹配输入的URLs的知识,最后剩下的是写一个方法,将我们声明的路径转换成它们等价的正则表达式模式。
要做这个我们将使用另一个正则表达式(接下来将全是正则表达式),为了让我们路径中的变量转换成正则表示式模式,那这里作为示范我们将将“”转换成“(?P.+)”。
听起来太简单了!我们将可以只用一行新代码实现它。
def build_route_pattern(route):
route_regex = re.sub(r'(&w+&)', r'(?P1.+)', route)
pile("^{}$".format(route_regex))
print build_route_pattern('/hello/&username&')
这里我们用一个正则表达式代表所有出现的模式(一个包含在尖括号中的字符串),与它的正则表达式命名组等价。
re.sub的第一个参数 我们将我们的模式放进括号,目的是把它分配到第一个匹配组。在我们的第二个参数,我们可以使用第一匹配组的内容,方法是写1(2将是第二匹配组的内容,以此类推…….)
那么最后,输入模式
/hello/&username&
将给我们正则表达式:
^/hello/(?P&username&.+)$
让我们扫一眼上次我们写的简单NotFlask类。
class NotFlask():
def __init__(self):
self.routes = {}
def route(self, route_str):
def decorator(f):
self.routes[route_str] = f
return decorator
def serve(self, path):
view_function = self.routes.get(path)
if view_function:
return view_function()
raise ValueError('Route "{}"" has not been registered'.format(path))
app = NotFlask()
@app.route("/")
def hello():
return "Hello World!"
现在我们有一个新的改进方法用来匹配输入的路径,我们打算移除我们上一版实现时用到的原生字典。
让我们从改造我们的函数着手,以便于添加路径,这样我们就可以用(pattern, view_function)对列表代替字典保存我们的路径。
这意味着当一个程序员使用@app.route()装饰一个函数,我们将要尝试将他们的路径编译变成一个正则表达式,然后存储它,属于一个在我们新的路径列表里的装饰函数。
让我们看看实现代码:
class NotFlask():
def __init__(self):
self.routes = []
# Here's our build_route_pattern we made earlier
@staticmethod
def build_route_pattern(route):
route_regex = re.sub(r'(&w+&)', r'(?P1.+)', route)
pile("^{}$".format(route_regex))
def route(self, route_str):
def decorator(f):
# Instead of inserting into a dictionary,
# We'll append the tuple to our route list
route_pattern = self.build_route_pattern(route_str)
self.routes.append((route_pattern, f))
return decorator
我们也打算需要一个get_route_match方法,给它一个路径实例,将会尝试并找到一个匹配的view_function,或者返回None如果一个也找不到的话。
然而,如果找了到匹配的话,除了view_function之外,我们还需要返回一个东西,那就是我们包含之前捕获匹配组的字典,我们需要它来为视图函数传递正确的参数。
好了我们的get_route_match大概就长这样:
def get_route_match(path):
for route_pattern, view_function in self.routes:
m = route_pattern.match(path)
return m.groupdict(), view_function
return None
现在我们快要完成了,最后一步将是找出调用view_function的方法,使用来自正则表达式匹配组字典的正确参数。
调用一个函数的若干种方法
让我们回顾一下不同的方法调用一个python的函数。
比如像这样:
def hello_user(username):
return "Hello {}!".format(username)
最简单的(也许正是你所熟知的)办法是使用正则参数,在这里参数的顺序匹配我们定义的那些函数的顺序。
&&& hello_user("ains")
Hello ains!
另一种方法调用一个函数是使用关键词参数。关键词参数可以通过任何顺序指定,适合有许多可选参数的函数。
&&& hello_user(username="ains")
Hello ains!
在Python中最后一种调用一个函数的方法是使用关键词参数字典,字典中的关键词对应参数名称。我们告诉Python解包一个字典,并通过使用两个星号“**”来把它当作函数的关键词参数。 下面的代码段与上面的代码段完全一样,现在我们使用字典参数,我们可以在运行时动态创建它。
&&& kwargs = {"username": "ains"}
&&& hello_user(**kwargs)
Hello ains!
好了,还记得上面的groupdict()方法?就是那个同样的在正则表达式完成匹配后返回{“username”: “ains”}的家伙?那么现在我们了解了kwargs,我们能很容易向我们的view_function传递字典匹配,完成NotFlask!
那么让我们把这些都塞进我们最终的类中。
class NotFlask():
def __init__(self):
self.routes = []
@staticmethod
def build_route_pattern(route):
route_regex = re.sub(r'(&w+&)', r'(?P1.+)', route)
pile("^{}$".format(route_regex))
def route(self, route_str):
def decorator(f):
route_pattern = self.build_route_pattern(route_str)
self.routes.append((route_pattern, f))
return decorator
def get_route_match(self, path):
for route_pattern, view_function in self.routes:
m = route_pattern.match(path)
return m.groupdict(), view_function
return None
def serve(self, path):
route_match = self.get_route_match(path)
if route_match:
kwargs, view_function = route_match
return view_function(**kwargs)
raise ValueError('Route "{}"" has not been registered'.format(path))
接下来,就是见证奇迹的时刻,请看下面代码段:
app = NotFlask()
@app.route("/hello/")
def hello_user(username):
return "Hello {}!".format(username)
print app.serve("/hello/ains")
我们将得到输出:
Hello ains!
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具PS:react-route就是一个决定生成什么父子关系的组件,一般和layout结合起来,保证layout不行,内部的子html进行跳转
你会发现,它不是一个库,也不是一个框架,而是一个庞大的体系。想要发挥它的威力,整个技术栈都要配合它改造。你要学习一整套解决方案,从后端到前端,都是全新的做法。
举例来说,React 不使用 HTML,而使用 JSX 。它打算抛弃 DOM,要求开发者不要使用任何 DOM 方法。它甚至还抛弃了 SQL ,自己发明了一套查询语言 GraphQL 。当然,这些你都可以不用,React 照样运行,但是就发挥不出它的最大威力。
这样说吧,你只要用了 React,就会发现合理的选择就是,采用它的整个技术栈。
本文介绍 React 体系的一个重要部分:路由库。它是官方维护的,事实上也是唯一可选的路由库。它通过管理 URL,实现组件的切换和状态的变化,开发复杂的应用几乎肯定会用到。
本文针对初学者,尽量写得简洁易懂。预备知识是 React 的基本用法,可以参考我写的。
另外,我没有准备示例库,因为官方的非常棒,由浅入深,分成14步,每一步都有详细的代码解释。我强烈建议你先跟着做一遍,然后再看下面的API讲解。
一、基本用法
React Router 安装命令如下。
$ npm install -S react-router
使用时,路由器Router就是React的一个组件。
import { Router } from 'react-router';
render(&Router/&, document.getElementById('app'));
Router组件本身只是一个容器,真正的路由要通过Route组件定义。
import { Router, Route, hashHistory } from 'react-router';
&Router history={hashHistory}&
&Route path="/" component={App}/&
), document.getElementById('app'));
上面代码中,用户访问根路由/(比如/),组件APP就会加载到document.getElementById('app')。
你可能还注意到,Router组件有一个参数history,它的值hashHistory表示,路由的切换由URL的hash变化决定,即URL的#部分发生变化。举例来说,用户访问/,实际会看到的是/#/。
Route组件定义了URL路径与组件的对应关系。你可以同时使用多个Route组件。
&Router history={hashHistory}&
&Route path="/" component={App}/&
&Route path="/repos" component={Repos}/&
&Route path="/about" component={About}/&
上面代码中,用户访问/repos(比如http://localhost:8080/#/repos)时,加载Repos组件;访问/about(http://localhost:8080/#/about)时,加载About组件。
二、嵌套路由
Route组件还可以嵌套。
&Router history={hashHistory}&
&Route path="/" component={App}&
&Route path="/repos" component={Repos}/&
&Route path="/about" component={About}/&
上面代码中,用户访问/repos时,会先加载App组件,然后在它的内部再加载Repos组件。
App组件要写成下面的样子。
export default React.createClass({
render() {
return &div&
{this.props.children}
上面代码中,App组件的this.props.children属性就是子组件。
子路由也可以不写在Router组件里面,单独传入Router组件的routes属性。
let routes = &Route path="/" component={App}&
&Route path="/repos" component={Repos}/&
&Route path="/about" component={About}/&
三、 path 属性
Route组件的path属性指定路由的匹配规则。这个属性是可以省略的,这样的话,不管路径是否匹配,总是会加载指定组件。
请看下面的例子。
&Route path="inbox" component={Inbox}&
&Route path="messages/:id" component={Message} /&
上面代码中,当用户访问/inbox/messages/:id时,会加载下面的组件。
如果省略外层Route的path参数,写成下面的样子。
&Route component={Inbox}&
&Route path="inbox/messages/:id" component={Message} /&
现在用户访问/inbox/messages/:id时,组件加载还是原来的样子。
四、通配符
path属性可以使用通配符。
通配符的规则如下。
(1):paramName
:paramName匹配URL的一个部分,直到遇到下一个/、?、#为止。这个路径参数可以通过this.props.params.paramName取出。
()表示URL的这个部分是可选的。
*匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
** 匹配任意字符,直到下一个/、?、#为止。匹配方式是贪婪模式。
path属性也可以使用相对路径(不以/开头),匹配时就会相对于父组件的路径,可以参考上一节的例子。嵌套路由如果想摆脱这个规则,可以使用绝对路由。
路由匹配规则是从上到下执行,一旦发现匹配,就不再其余的规则了。
&Route path="/comments" ... /&
&Route path="/comments" ... /&
上面代码中,路径/comments同时匹配两个规则,第二个规则不会生效。
设置路径参数时,需要特别小心这一点。
上面代码中,用户访问/about/me时,不会触发第二个路由规则,因为它会匹配/:userName/:id这个规则。因此,带参数的路径一般要写在路由规则的底部。
此外,URL的查询字符串/foo?bar=baz,可以用this.props.location.query.bar获取。
五、IndexRoute 组件
下面的例子,你会不会觉得有一点问题?
上面代码中,访问根路径/,不会加载任何子组件。也就是说,App组件的this.props.children,这时是undefined。
因此,通常会采用{this.props.children || &Home/&}这样的写法。这时,Home明明是Accounts和Statements的同级组件,却没有写在Route中。
IndexRoute就是解决这个问题,显式指定Home是根路由的子组件,即指定默认情况下加载的子组件。你可以把IndexRoute想象成某个路径的index.html。
现在,用户访问/的时候,加载的组件结构如下。
这种组件结构就很清晰了:App只包含下级组件的共有元素,本身的展示内容则由Home组件定义。这样有利于代码分离,也有利于使用React Router提供的各种API。
注意,IndexRoute组件没有路径参数path。
六、Redirect 组件
&Redirect&组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。
现在访问/inbox/messages/5,会自动跳转到/messages/5。
七、IndexRedirect 组件
IndexRedirect组件用于访问根路由的时候,将用户重定向到某个子组件。
上面代码中,用户访问根路径时,将自动重定向到子组件welcome。
Link组件用于取代&a&元素,生成一个链接,允许用户点击后跳转到另一个路由。它基本上就是&a&元素的React 版本,可以接收Router的状态。
render() {
return &div&
&ul role="nav"&
&li&&Link to="/about"&About&/Link&&/li&
&li&&Link to="/repos"&Repos&/Link&&/li&
如果希望当前的路由与其他路由有不同样式,这时可以使用Link组件的activeStyle属性。
&Link to="/about" activeStyle={{color: 'red'}}&About
上面代码中,当前页面的链接会红色显示。
另一种做法是,使用activeClassName指定当前路由的Class。
上面代码中,当前页面的链接的class会包含active。
在Router组件之外,导航到路由页面,可以使用浏览器的History API,像下面这样写。
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
九、IndexLink
如果链接到根路由/,不要使用Link组件,而要使用IndexLink组件。
这是因为对于根路由来说,activeStyle和activeClassName会失效,或者说总是生效,因为/会匹配任何子路由。而IndexLink组件会使用路径的精确匹配。
上面代码中,根路由只会在精确匹配时,才具有activeClassName。
另一种方法是使用Link组件的onlyActiveOnIndex属性,也能达到同样效果。
&Link to="/" activeClassName="active" onlyActiveOnIndex={true}&
实际上,IndexLink就是对Link组件的onlyActiveOnIndex属性的包装。
十、histroy 属性
Router组件的history属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。
history属性,一共可以设置三种值。
browserHistory
hashHistory
createMemoryHistory
如果设为hashHistory,路由将通过URL的hash部分(#)切换,URL的形式类似</#/some/path。
import { hashHistory } from 'react-router'
&Router history={hashHistory} routes={routes} /&,
document.getElementById('app')
如果设为browserHistory,浏览器的路由就不再通过Hash完成了,而显示正常的路径</some/path,背后调用的是浏览器的History API。
import { browserHistory } from 'react-router'
&Router history={browserHistory} routes={routes} /&,
document.getElementById('app')
但是,这种情况需要对。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误。
如果开发服务器使用的是webpack-dev-server,加上--history-api-fallback参数就可以了。
$ webpack-dev-server --inline --content-base . --history-api-fallback
createMemoryHistory主要用于服务器渲染。它创建一个内存中的history对象,不与浏览器URL互动。
const history = createMemoryHistory(location)
十一、表单处理
Link组件用于正常的用户点击跳转,但是有时还需要表单跳转、点击按钮跳转等操作。这些情况怎么跟React Router对接呢?
下面是一个表单。
&form onSubmit={this.handleSubmit}&
第一种方法是使用browserHistory.push
import { browserHistory } from 'react-router'
第二种方法是使用context对象。
export default React.createClass({
十二、路由的钩子
每个路由都有Enter和Leave钩子,用户进入或离开该路由时触发。
上面的代码中,如果用户离开/messages/:id,进入/about时,会依次触发以下的钩子。
/messages/:id的onLeave
/inbox的onLeave
/about的onEnter
下面是一个例子,使用onEnter钩子替代&Redirect&组件。
&Route path="inbox" component={Inbox}&
path="messages/:id"
({params}, replace) =& replace(`/messages/${params.id}`)
下面是一个高级应用,当用户离开一个路径的时候,跳出一个提示框,要求用户确认是否离开。
const Home = withRouter(
React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(
this.props.route,
this.routerWillLeave
routerWillLeave(nextLocation) {
上面代码中,setRouteLeaveHook方法为Leave钩子指定routerWillLeave函数。该方法如果返回false,将阻止路由的切换,否则就返回一个字符串,提示用户决定是否要切换。
阅读(...) 评论()2016年1月 总版技术专家分月排行榜第二2015年11月 总版技术专家分月排行榜第二2015年10月 总版技术专家分月排行榜第二
优秀小版主
2016年1月 总版技术专家分月排行榜第二2015年11月 总版技术专家分月排行榜第二2015年10月 总版技术专家分月排行榜第二
优秀小版主
2016年1月 总版技术专家分月排行榜第二2015年11月 总版技术专家分月排行榜第二2015年10月 总版技术专家分月排行榜第二
优秀小版主
2017年2月 总版技术专家分月排行榜第三
2017年5月 .NET技术大版内专家分月排行榜第一2017年4月 .NET技术大版内专家分月排行榜第一2017年3月 .NET技术大版内专家分月排行榜第一2017年2月 .NET技术大版内专家分月排行榜第一2016年10月 .NET技术大版内专家分月排行榜第一2016年8月 .NET技术大版内专家分月排行榜第一2016年7月 .NET技术大版内专家分月排行榜第一
2016年1月 总版技术专家分月排行榜第二2015年11月 总版技术专家分月排行榜第二2015年10月 总版技术专家分月排行榜第二
优秀小版主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
angular1中可以根据routeparam加载相应的controller和template, ng2的routeconfig中有个loader方法, 文档提到promise, 不知道怎么取到routeparam来动态加载component?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
下面的代码是异步加载,而非动态加载。
{ path: '/reviewTask', loader: () =& require('./review/review')('ReviewTask'), name: 'ReviewTask'},
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:}

我要回帖

更多关于 route.path 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信