flask--app.add_url_rule()函数 和 类视图详解
flask--app.add_url_rule()函数 和 类视图详解
- app.add_url_rule()函数
在flask中,我们知道给一个函数添加url的时候,只需要使用装饰器@app.route('')装饰对应的函数就可以了。为什么这个装饰器就可以给函数视图 添加url规则呢?查看app.route()源码发现,这个装饰器在里面调用的另外一个方法self.add_url_rule,这里的self就是app这个实例对象。
app.route()源码内容
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
那么app.route
这个装饰器就是通过调用add_url_rule
这个方法生成函数视图对应的url的,那么我们可不可以我们自己直接调用这个方法来生成函数对应的url规则呢?答案是肯定的。
示例如下:
from flask import Flask
app = Flask(__name__)
def index():
return 'index'
app.add_url_rule('/index/',endpoint='index',view_func=index)
add_url_rule三个参数解释:
- 第一个参数:函数对应的url规则,满足条件和app.route()的第一个参数一样,必须以'/'开始
- endpoint:站点,就是在使用url_for()进行反转的时候,这个里面传入的第一个参数就是这个endpoint对应的值。这个值也可以不指定,那么默认就会使用函数的名字作为endpoint的值
- view_func:对应的函数,即这个url对应的是哪一个函数,注意,这里函数只需要写函数名字,不要加括号,加括号表示将函数的返回值传给了view_func参数了。程序就会直接报错。
# 正确的方式
app.add_url_rule('/index/',endpoint='index',view_func=index)
# 错误的方式
app.add_url_rule('/index/',endpoint='index',view_func=index())
- methods:
add_url_rule
还可以传入一个methods
参数,用来指定这个函数对应的访问规制,如post,get请求等,默认是get
请求,并且只允许get
请求。当我们需要改变请求方式的时候,我们就可以传入这个参数了。
# 指定一种
app.add_url_rule('/index/',endpoint='index',view_func=index,methods=['POST'])
# 指定多种
app.add_url_rule('/index/',endpoint='index',view_func=index,methods=['POST','get'])
注意:
- 就算是只指定一种请求方式,也必须的用列表或元祖包裹起来,最好是用列表,元祖在某些情况下可能会出错。
- 当元祖里面只有一个值得时候,后面必须的加一个
,
,('post',)
。
2.什么是类视图
我们知道,在flask中,我们写的视图都是以函数形式写的,所以一般简称函数视图。其实视图我们也可以使用类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图之后,我们还需要通过app.add_url_rule( url_rule, view_func )来进行注册。在flask中,有两种类视图。
3.标准类视图
标准类视图是继承自flask.views.View,并且在子类中必须实现dispatch_request方法,这个方法就是相当于视图函数,所有的逻辑操作我们都要放在这个里面完成。也必须的返回一个值,函数视图能返回什么类型的值,这里就可以返回什么类型的值。其实类视图和函数视图基本都是一样的,只是我们在做添加url规则的时候不一样而已。
from flask import Flask,views
app = Flask(__name__)
class ProfileView(views.View):
def dispatch_request(self):
return '个人中心页面'
app.add_url_rule('/profile/',endpoint='profile',view_func=ProfileView.as_view('profile'))
add_url_rule里面的参数的意思相信大家也知道了,这里说一下as_view里面传入的参数的意思吧。
- View.as_view(’<指定函数的名称>’):因为我们所以的类视图都会继承自View类,并且都要重写dispatch_request方法,那么flask怎么知道我们绑定的是哪一个类的dispatch_request方法呢?就是通过这个参数来指定的。相当于给我们的dispatch_request方法起一个名字。当我们没有写endpoint参数的时候,那么endpoint的值就会是我们这个函数的名字。通过url_for进行反转的时候也是用的这个值。如果指定了endpoint的值,url_for就会使用endpoint的值,我们指定的函数名称对于我们来说没有什么太大的用处了,但是flask内部还是很有用处的。
4. 基于调度方法的视图
在flask中,还提供了另外一种类视图flask.views.MethodView
,对每个HTTP的请求方法执行不同的函数,映射到对应小写的同名方法上面。例如:
class LoginView(views.MethodView):
def get(self):
return 'get 请求'
def post(self):
return 'post 请求'
app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
这样,当我们以GET请求访问/login/页面的时候,就会执行get方法,以POST请求访问/login/页面的时候,就会执行post方法。
比如我们登陆的时候,如果用户使用的是get方法请求我们的页面,那么我们就渲染一个html页面给客户端,而当使用post方法请求的时候,我们就对上传的数据进行处理,然后返回相应的信息。
5.视图使用装饰器
假设我们现在有一个需求:如果用户请求的时候以get请求传入了username参数,我们就认为登陆了(模拟登陆的效果。),可以访问个人中心页面,否则的话就认为没有登陆。重定向到登陆页面。
这种需求我们一把都不会在视图中的逻辑代码中判断,而会定义一个装饰器。
定义装饰器:
from flask import Flask,views,request,redirect,url_for
from functools import wraps
app = Flask(__name__)
def login_require(fn):
@wraps(fn)
def wrapper(*args,**kwargs):
username = request.args.get('username')
if username and username == 'xxx':
return fn(*args,**kwargs)
else:
return redirect( url_for('login') )
return wrapper
-
- 函数视图使用装饰器。
上面我们就把装饰器定义好了,接下里我们就要开始使用这个装饰器了
@app.route('/login/')
def login():
return 'login page'
@app.route('/profile/')
@login_require # 使用我们写的login_require装饰器 这个装饰器必须放在@app.route()装饰器的下面
def profile():
return '个人中心'
这样,我们就对我们的profile这个视图进行了装饰,如果输入网址为127.0.0.1:5000/profile/的时候,就会重定向到login视图中去。如果输入网址为127.0.0.1:5000/profile/?username=xxx才会被允许进入profile视图。当然,这里只是假设认为传入了username参数并且等于xxx就认为登陆了,在项目中肯定不会这样写的。在这里我们也只是为了知道装饰器的使用而已。
注意:
- 如果我们使用app.route添加url规则的话,那么我们自己写的装饰器就必须放在app.route的下面。否则的话我们写的装饰器是没有作用的
- 如果有多个装饰器的话。每个装饰器都必须放在app.route下面,然后就可以随便放置了。
3.类视图使用装饰器
使用views.View方法
class ProfileView(views.View):
# 将这个视图所有的装饰器用decorators这个列表装起来
decorators = [login_require]
def dispatch_request(self):
return '个人中心页面'
# 当然也可以直接装饰这个函数
class ProfileView(views.View):
@login_require
def dispatch_request(self):
return '个人中心页面'
app.add_url_rule('/profile/',view_func=Profile.as_view('profile'))
上面的两种方式都是可以的,至于用哪一种就看心情吧
- 使用views.MethodView类
MethodView有三种方法进行装饰。
# 第一种,直接对相应的请求进行装饰
class ProfileView(views.MethodView):
@login_require
def get(self):
return 'profile from get method'
def post(self):
return 'profile from post method'
# 第二种,重写dispatch_request方法,然后进行装饰
class ProfileView(views.MethodView):
@login_require
def dispatch_request(self,*args,**kwargs):
return super().dispatch_request(*args,**kwargs)
def get(self):
return 'profile from get method'
def post(self):
return 'profile from post method'
# 第三中,使用decorators属性
class ProfileView(views.MethodView):
decorators = [login_require]
def get(self):
return 'profile from get method'
def post(self):
return 'profile from post method'
app.add_url_rule('/profile/',view_func=Profile.as_view('profile'))
三种方式向使用哪一种都可以,看自己心情吧