20标准类视图、基于调度方法的类视图、使用装饰器的类视图
一:标准类视图:https://www.bilibili.com/video/av62010252/?p=36
1, 标准类视图:必须继承自 views.View(from flask import Flask,views)
2,必须实现dispatch_request(self)方法,以后请求过来后,都会执行这个方法,这个方法的返回值就相当于是之前的函数视图一样。也必须返回“”Response“。”
3,必须通过
“app.add_url_rule('/list/',endpoint='list',view_func=ListView.as_view('list'))”
来做URL与类视图的映射,‘’view_func‘’这个参数,需要使用类视图下的“as_view”类方法转换:
4,如果指定了endpoint,那么使用url_for时候就必须使用它。如果没有指定,那么默认为类视图名字。
代码示例:
1 from flask import Flask,views 2 3 app = Flask(__name__) 4 5 class ListView(views.View): 6 def dispatch_request(self): 7 return "list view" 8 9 app.add_url_rule('/list/',endpoint='list',view_func=ListView.as_view('list')) 10 11 12 @app.route('/') 13 def hello_world(): 14 return 'Hello World!' 15 16 17 if __name__ == '__main__': 18 app.run()
那么,为什么我们为什么有函数视图还要用类视图呢?首先,因为类比函数要功能多,封装性也更强。封装性在多次调用时候体现。
示例:
加入有几个URL需要返回json数据,那么:
1 from flask import Flask,views,jsonify,render_template 2 3 app = Flask(__name__) 4 5 6 #加入有几个URL需要返回json数据 7 class JsonView(views.View): 8 def get_data(self): 9 raise NotImplementedError 10 def dispatch_request(self): 11 return jsonify(self.get_data()) 12 13 class ListView(JsonView): 14 def get_data(self): 15 return {'username':'zy','password':'123'} 16 app.add_url_rule('/list/',endpoint='list',view_func=ListView.as_view('list')) 17 18 19 #有几个视图,需要返回相同的变量 20 class ADSView(views.View): 21 def __init__(self): 22 super(ADSView, self).__init__() 23 self.content = { 24 'ads':'This is ads!' 25 } 26 27 class LoginView(ADSView): 28 def dispatch_request(self): 29 self.content.update({ 30 'user': 'zy' 31 }) 32 return render_template('login.html',**self.content) 33 34 class RegistView(ADSView): 35 def dispatch_request(self): 36 return render_template('regist.html',**self.content) 37 app.add_url_rule('/login/',view_func=LoginView.as_view('login')) 38 app.add_url_rule('/regist/',view_func=RegistView.as_view('regist')) 39 40 41 @app.route('/') 42 def hello_world(): 43 return 'Hello World!' 44 45 46 if __name__ == '__main__': 47 app.run()
详细解释:
行16中URL输入http://127.0.0.1:5000/list/时,视图函数会调用类视图ListView,而类视图中必须要有dispatch_request(self),可是这个ListView是子视图,没有这个函数,
这时候需要调用上层的父类JsonView,由其调用dispatch_request(self)函数,执行jsonify(self.get_data())代码,因为是子类调用它,所以这个jsonify(self.get_data())
中的self就为子类本身,即调用子类中的get_data()函数。
那么为什么父类中还有get_data函数呢,它也没啥用?因为JsonView是不能直接用的,他只是一个抽象的,并不能当做实际视图来用,所以他下面的get_data也不能用,因此用raise。
login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登陆页面广告</h1> {{ ads }} === {{ user }} </body> </html>
类视图有以下好处:
可以继承,把一些共性的东西抽取出来放在父视图中,子视图直接拿来用就可以了,与函数视图对比那个方便就用哪个。
二,基于调度方法的类视图 https://www.bilibili.com/video/av62010252/?p=36
先贴一段代码:
1 from flask import Flask,views,render_template,request 2 3 app = Flask(__name__) 4 5 6 @app.route('/') 7 def hello_world(): 8 return 'Hello World!' 9 10 class LoginView(views.MethodView): 11 def get(self): 12 return render_template('login.html') 13 def post(self): 14 username = request.form.get('name') 15 if username == 'zy': 16 return 'Login success' 17 else: 18 return 'faied' 19 20 app.add_url_rule('/login/',endpoint='login',view_func=LoginView.as_view('list')) 21 22 if __name__ == '__main__': 23 app.run()
注意:基于调度方法的类视图是MethodView,而非View。
如果我们要加上错误后的提示信息应该怎么加呢?
1 from flask import Flask,views,render_template,request 2 3 app = Flask(__name__) 4 5 6 @app.route('/') 7 def hello_world(): 8 return 'Hello World!' 9 10 class LoginView(views.MethodView): 11 def __geterror(self,error): 12 return render_template('login.html',error=error) 13 def get(self): 14 return render_template('login.html') 15 def post(self): 16 username = request.form.get('name') 17 if username == 'zy': 18 return 'Login success' 19 else: 20 return self.__geterror(error='密码或账户错误') 21 22 app.add_url_rule('/login/',endpoint='login',view_func=LoginView.as_view('list')) 23 24 if __name__ == '__main__': 25 app.run()
三,使用装饰器的类视图
普通使用装饰器的函数视图,代码:
1 from flask import Flask,request,render_template 2 from functools import wraps 3 app = Flask(__name__) 4 5 6 @app.route('/') 7 def hello_world(): 8 return 'Hello World!' 9 10 def login_required(func): 11 @wraps(func) #这里为什么要加这个呢?因为为了防止func函数的属性丢失。 12 def wrapper(*args,**kwargs): 13 user = request.args.get('user') 14 #这里是arg,所以应该写为/set/?user=zy 15 if user and user == 'zy': 16 return func(*args,**kwargs) 17 else: 18 return '请先登录' 19 return wrapper 20 21 @app.route('/set/') 22 @login_required 23 def set(): 24 return '这里是设置界面' 25 26 27 28 29 if __name__ == '__main__': 30 app.run()
那么使用装饰器的类方法的实现怎么弄呢?
1 from flask import Flask,request,render_template 2 from functools import wraps 3 app = Flask(__name__) 4 5 6 @app.route('/') 7 def hello_world(): 8 return 'Hello World!' 9 10 def login_required(func): 11 @wraps(func) #这里为什么要加这个呢?因为为了防止func函数的属性丢失。 12 def wrapper(*args,**kwargs): 13 user = request.args.get('user') 14 #这里是arg,所以应该写为/set/?user=zy 15 if user and user == 'zy': 16 return func(*args,**kwargs) 17 else: 18 return '请先登录' 19 return wrapper 20 21 @app.route('/set/') 22 @login_required 23 def set(): 24 return '这里是设置界面' 25 26 from flask import views 27 class ProfileView(views.View): 28 decorators = [login_required] #直接这样就行了,不用打括号 29 def dispatch_request(self): 30 return '这里是设置界面' 31 app.add_url_rule('/pro/',endpoint='profile',view_func=ProfileView.as_view('profile')) 32 33 34 35 36 37 if __name__ == '__main__': 38 app.run()