当前位置: 首页 > Web前端 > HTML

flask之三:视图高级

时间:2023-04-02 11:19:42 HTML

视图高级app.route和app.add_url_ruleapp.add_url_ruleapp.add_url_rule('/list/',endpoint='myweb',view_func=my_list)这个方法是用来添加url与视图函数的映射。如果没有填写endpoint那么会默认使用view_func的名字来作为endpoint。因此在使用url_for的时候,就要看在映射的时候有没有传递endpoint参数,如果传递了,那么就使用endpoint指定的字符串。付过没有使用的话就使用view_func定义的名字。app.route(rule,**options)装饰器这个装饰器的底层就是用add_url_rule来实现url与视图函数映射的。小例子如下:from flask import Flask,url_forapp = Flask(__name__)app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True})@app.route('/',endpoint='index')def hello_world(): print(url_for('myweb')) return 'Hello World!'def my_list(): return 'list page!'app.add_url_rule('/list/',endpoint='myweb',view_func=my_list)#请求上下文的定义,结合url_forwith app.test_request_context(): print(url_for('index'))if __name__ == '__main__': app.run()类视图之前我们接触的视图都是函数,所以一般简称视图函数。其实视图也可以基于类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图还需要通过app.add_url_rule(url_rule,view_func)来进行注册。以下将对两种类视图进行讲解标准视图标准类视图必须继承自flask.views.View必须实现dispatch_request方法,以后请求过来以后,会执行这个方法。这个方法的返回值就相当于是之前的函数视图一样,也必须返回Request或者子类的对象(字符串或者元组)。必须是通过app.add_url_rule(rule,endpoint,view_func)来做url映射。view_func这个参数,要使用as_view这个方法来转换如果指定了endpoint,那么在使用url_for反转的时候,就要使用endpoint指定的那个值,如果没有指定那个值,就使用as_view中指定的视图名字来作为反转。类视图有以下的好处,可以将一些共性的东西抽取出来放到父视图中,子视图直接继承就可以了,但是也不是说所有的视图都要使用类视图,这个要根据实际情况来定。小例子:from flask import Flask,views,url_forapp = Flask(__name__)class ListView(views.View): def dispatch_request(self): return 'list view'#app.add_url_rule('/list/',endpoint='list',view_func=ListView.as_view('list'))app.add_url_rule('/list/',view_func=ListView.as_view('list'))with app.test_request_context(): print(url_for('list'))@app.route('/')def hello_world(): return 'Hello World!'if __name__ == '__main__': app.run(debug=True)类视图的小例子:from flask import Flask,url_for,views,jsonify,render_templateapp = Flask(__name__)app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True})#自定义封装,返回json数据class JSONView(views.View): def get_data(self): raise NotImplementedError def dispatch_request(self): return jsonify(self.get_data())class ListView(JSONView): def get_data(self): return { 'username':'wanghui', 'password':123456, }app.add_url_rule('/list/',endpoint='my_list',view_func=ListView.as_view('list'))#有几个视图,需要返回相同的变量(广告页面)class ADSView(views.View): def __init__(self): super(ADSView, self).__init__() self.context = { 'ads':"今年过节不收礼,收礼只收脑白金" }class RegistView(ADSView): def dispatch_request(self): self.context.update({'username':'abcd'}) return render_template('register.html',**self.context)class LoginView(ADSView): def dispatch_request(self): return render_template('login.html',**self.context)# class LoginView(views.View):# def dispatch_request(self):# return render_template('login.html',ads="今年过节不收礼,收礼只收脑白金")# class RegistView(views.View):# def dispatch_request(self):# return render_template('register.html',ads="今年过节不收礼,收礼只收脑白金")app.add_url_rule('/login/',view_func=LoginView.as_view('login'))app.add_url_rule('/regist/',view_func=RegistView.as_view('regist'))@app.route('/')def hello(): return "heello"if __name__ == '__main__': app.run()基于调度方法的视图根据请求方法来执行不同的方法的,如果用户发送的是get请求,就会执行这个类的get方法;如果用户发起的是post方法,就会执行这个类的post方法。其他的方法类似,这种方法使得代码更加简洁,使得执行get请求的代码放在get方法中,post请求的代码放在posy方法中。就不需要跟之前的request.method == 'POST'来搞了。小例子pyfrom flask import Flask,views,render_template,requestapp = Flask(__name__)class LoginView(views.MethodView): def __render(self,error=None): return render_template('login.html',error=error) def get(self,error=None): # return render_template('login.html',error=error) return self.__render() def post(self): username = request.form.get('username') password = request.form.get('password') if username == 'wanghui' and password == '111111': return 'login success' else: # return render_template('login.html',error="username or password error,retry!") # return self.get(error="username or password error,retry!") return self.__render(error="username or password error,retry!")app.add_url_rule('/login/',view_func=LoginView.as_view('login'))@app.route('/')def hello_world(): return 'Hello World!'if __name__ == '__main__': app.run(debug=True,port=9090)login.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>login</title></head><body><form action="" method="post"> <table> <tr> <td>用户名</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密码</td> <td><input type="password" name="password"></td> </tr> <tr> <td></td> <td><input type="submit" value="立即登陆"></td> </tr> </table> {% if error %} <p style="color: red;">{{ error }}</p> {% endif %}</form></body></html>类视图上面使用装饰器两种类型的装饰器如果使用的是函数视图, 那么定义的装饰器必须放在app.route下面,否则起不到任何作用类视图的装饰器,需要重写类视图的decorators类属性,里面装的就是所有的装饰器小例子:from flask import Flask,request,viewsfrom functools import wrapsapp = Flask(__name__)#定义装饰器def login_required(func): @wraps(func) def wrapper(*args,**kwargs): username = request.args.get('username') if username and username == 'wanghui': return func(*args,**kwargs) else: return "请先登录" return wrapper@app.route('/settings/')@login_requireddef settings(): return '这是设置页面'#这样请求就行http://127.0.0.1:9091/settings/?username=wanghui#类视图添加装饰器class ProfileView(views.View): decorators = [login_required] def dispatch_request(self): return "这是个人中心"app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))蓝图将大型项目分层解耦,实现模块化,结构更加清晰。可以将相同的模块放在同一个蓝图下,同一个文件夹中。方便管理。基本语法:在蓝图文件中导入Blueprintfrom flask import Blueprintuser_bp = Blueprint('user',__name__) #相当于是定义`app = Flask(__name__)`在主app文件中注册蓝图from blueprints.user import user_bpapp.regist_blueprint(user_bp) #实现注册蓝图如果想要某个蓝图下的所有URL的时候有个前缀,那么可以在定义蓝图的时候加上url_prefixfrom flask import Blueprintuser_bp = Blueprint('user',__name__,url_prefix='/user') # 特别注意斜杠蓝图中的模板文件蓝图模板文件查找:如果项目中的templates文件夹中存在对应的模板文件,就可以直接使用如果项目中的templates文件夹中存在相应的模板文件,那么就在定义蓝图的指定路径中查找,可以设置相对路径,就要在蓝图文件相同路径下的文件夹。from flask import Blueprint,render_templatenews_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='news')@news_bp.route('/list/')def news_list(): return render_template('news_list.html')蓝图中的静态文件查找:在模板文件中,加载静态文件,如果使用url_for('static'),那么只会在app指定的静态文件夹目录下查找静态文件如果在加载静态文件的时候置顶了蓝图的名字,比如url_for('news.static'),那么会到蓝图指定的static_folder下查找静态文件。url_for反转蓝图注意事项注意url_for到蓝图中的视图函数的时候,要反转蓝图中的视图函数为url,那么就用该在使用url_for的时候使用url_for('news.news_list')不然就找不到这个endpoint。即使在同一个蓝图中,反转视图函数,也要制定蓝图的名字子域名实现使用蓝图技术在创建蓝图对象的时候要使用subdomain来指定这个子域名from flask import Blueprintcms_bp = Blueprint('cms',__name__,subdomain='cms')需要在app文件中配置app.config['SERVER_NAME']='baidu.com'来指定跟域名app.config['SERVER_NAME'] = 'crop.com:9099'修改hosts文件配置解析127.0.0.1 crop.com127.0.0.1 cms.crop.com5.访问cms.crop.com:9099综合实例代码目录结构blue_print_e├── blue_print_e.py├── blueprints│ ├── bok.py│ ├── cms.py│ ├── movie.py│ ├── news_css│ │ └── news_list.css│ ├── news.py│ ├── news_tmp│ │ └── news_list.html│ └── user.py├── static│ └── news_list.css└── templates ├── index.html └── news_list.html主app文件blue_print_e.py from flask import Flask,url_for,render_templatefrom blueprints.user import user_bpfrom blueprints.news import news_bpfrom blueprints.cms import cms_bpapp = Flask(__name__)app.config['SERVER_NAME'] = 'crop.com:9099'app.register_blueprint(user_bp)app.register_blueprint(news_bp)app.register_blueprint(cms_bp)# ip地址不能有子域名@app.route('/')def hello_world(): print(url_for('news_tmp.news_list')) #使用蓝图名字.视图函数的名字 return render_template('index.html')if __name__ == '__main__': app.run(debug=True,port=9099)blueprints/news.py#!/usr/bin/env python# -*- coding: utf-8 -*-from flask import Blueprint,render_template,url_fornews_bp = Blueprint('news_tmp',__name__,url_prefix='/news_tmp',template_folder='news_tmp',static_folder='news_css')@news_bp.route('/list/')def news_list(): print(url_for('news.news_detail')) return render_template('news_list.html')@news_bp.route('/detail')def news_detail(): return "详情页面"blueprints/user.py#!/usr/bin/env python# -*- coding: utf-8 -*-from flask import Blueprintuser_bp = Blueprint('user',__name__,url_prefix='/user')@user_bp.route('/profile/')def profile(): return "个人中心"@user_bp.route('/settings/')def settings(): return "设置页面"blueprint/cms.py#!/usr/bin/env python# -*- coding: utf-8 -*-from flask import Blueprintcms_bp = Blueprint('cms',__name__,subdomain='cms')@cms_bp.route('/')def index(): return 'cms index'blueprints/news_css/body { color: fuchsia; font-size: 90px; background: red;}