3.flask视图进阶
1.add_url_rule和app.route原理剖析
from flask import Flask app = Flask(__name__) # 下面是我们定义一个路由和对应视图的常用方法 ''' @app.route(r"/index") def index(): return "index" ''' # 这种方法等价于 def index(): return "index" app.add_url_rule(r"/index", view_func=index) # 这种方式同样可以将路由和视图函数绑定在一起
from flask import Flask, url_for app = Flask(__name__) def index(): return "index" # 在add_url_rule中还有一个endpoint参数,这个参数也是通过url_for来使用的 app.add_url_rule(r"/index", view_func=index, endpoint="satori") @app.route(r"/mashiro") def mashiro(): # 如果我们此时想获取index函数对应的路由,那么不能通过index来获取 # url_for()中不可以传index,而是要传endpoint return url_for("satori") if __name__ == '__main__': app.run(host="localhost", port=8888)
from flask import Flask, url_for app = Flask(__name__) # 我们在定义的时候也可以指定一个endpoint # 如果没指定,那么默认使用函数进行url的反向解析,如果指定了,则使用endpoint。 # 但是add_url_rule则必须使用endpoint @app.route(r"/satori", endpoint="aaa") def satori(): return "satori" @app.route(r"/koishi") def koishi(): return url_for("aaa") # 显然访问koishi就会在页面上显示相应的信息,并且url_for不能单独定义在外面,否则报错 # 如果我想在不访问页面的情况下就获取呢? with app.test_request_context(): print(url_for("aaa")) if __name__ == '__main__': app.run(host="localhost", port=8888)
其实app.route本质上还是调用了app.add_url_rule,我们可以看一下源码
def route(self, rule, **options): # 首先route是一个装饰器,当我们往route里面传参的时候,会先执行这个函数 # 返回一个decorator,然后装饰视图函数 # endpoint就是我们在route中传的endpoint,没有传,就是None # 然后调用self.add_url_rule,将参数按照相应顺序传进去 def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
2.标准类视图
from flask import Flask, views app = Flask(__name__) # 除了视图函数,我们也可以使用视图类 # 但是使用类,需要注意一点,那就是定义路由的时候,不能够使用装饰器的方式,要通过add_url_rule的方式 class Myview(views.View): # 定义一个视图类,这个类必须要继承views.View # 然后实现其内部的一个方法,这个方法必须实现,是专门用来处理请求的 def dispatch_request(self): return "这是一个视图类" # 将类和路由组合起来,view_func则是视图类调用as_view()方法的返回值,返回的是一个函数 # as_view的参数随便传一个就行,关于endpoint,如果不写,那么在反向解析的时候,使用as_view里面传入的参数 app.add_url_rule(r"/first_view", view_func=Myview.as_view("first_view")) if __name__ == '__main__': app.run(host="localhost", port=8888)
3.基于调度方法的类视图
from flask import Flask, views app = Flask(__name__) class Satori(views.MethodView): # 定义的类要继承自views.MethodView def get(self): return "get" def post(self): return "post" # 此时有点类似于tornado,当get请求到来,就触发get方法,post请求触发post方法 # 当然 同样需要注册 app.add_url_rule(r"/satori", view_func=Satori.as_view("satori")) if __name__ == '__main__': app.run(host="localhost", port=8888)
我们可以做一个登录界面,如果输入正确那么返回页面,输入错误返回提示:用户名或者密码错误
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login" 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" name="提交"></td> </tr> </table> {% if error %} <p style="color: red">{{error}}</p> {% endif %} </form> </body> </html>
from flask import Flask, views, request, render_template app = Flask(__name__) class Index(views.MethodView): def get(self): return render_template("1.html") def post(self): name = request.form.get("username") passwd = request.form.get("password") if name == "satori" and passwd == "123": return "欢迎来到古明地觉的避难小屋" return render_template("1.html", error="用户名或密码错误") app.add_url_rule("/login", view_func=Index.as_view("login")) if __name__ == '__main__': app.run(host="localhost", port=8888)
4.类视图中使用装饰器
先来一个基于普通函数视图的
from flask import Flask, views, request, render_template from functools import wraps app = Flask(__name__) def deco(func): @wraps(func) def wrapper(*args, **kwargs): username = request.args.get("username") password = request.args.get("password") if username == "satori" and password == "123": return func(*args, **kwargs) else: return "请输入正确的用户名或密码" return wrapper @app.route("/") @deco def hello(): return "hello world" if __name__ == '__main__': app.run()
基于类视图的装饰器
from flask import Flask, views, request, render_template from functools import wraps app = Flask(__name__) def deco(func): @wraps(func) def wrapper(*args, **kwargs): username = request.args.get("username") password = request.args.get("password") if username == "satori" and password == "123": return func(*args, **kwargs) else: return "请输入正确的用户名或密码" return wrapper # 使用类装饰器非常简单,flask都为我们考虑好了 class Hello(views.View): # decorators不能变,然后将装饰器以列表或者元组的形式进行赋值 decorators = [deco] def dispatch_request(self): return "hello satori" app.add_url_rule("/", view_func=Hello.as_view("hello")) if __name__ == '__main__': app.run()
5.蓝图的基本使用
蓝图,和我们平常说的宏伟蓝图的蓝图有区别,flask的蓝图是为了将解耦,我们之前的所有程序都写在一个py文件里面,然而一旦程序代码多了,就显得很乱,所以需要分层解耦。
代码结构:
book.py
from flask import Blueprint # 第一个参数是py文件名,这个时候就不能使用Flask了 book_app = Blueprint("book", __name__) @book_app.route("/book/gone") def gone(): return "gone"
movie.py
from flask import Blueprint # 第一个参数是py文件名 movie_app = Blueprint("movie", __name__, url_prefix="/movie") # 如果加上了url_prefix,那么在访问的时候必须要加上url_prefix @movie_app.route("/kiminonawa") def kimi(): return "你的名字"
start.py
from flask import Flask # 将app导入进来 from blueprint.movie import movie_app from blueprint.book import book_app app = Flask(__name__) # 然后进行注册 app.register_blueprint(movie_app) app.register_blueprint(book_app) if __name__ == '__main__': app.run()
6.蓝图中模板文件寻找规则
首先我们一开始的templates文件夹是毫无疑问可以的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>我是主目录templates里的html文件</h2> </body> </html>
from flask import Blueprint, render_template # 第一个参数是py文件名,这个时候就不能使用Flask了 book_app = Blueprint("book", __name__) @book_app.route("/book/gone") def gone(): return render_template("1.html")
但是如果我不想在templates文件夹里面找呢?那么可以单独指定文件夹
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>我是blueprint下的666文件里面的html</h2> </body> </html>
from flask import Blueprint, render_template # 可以指定template_folder,这个文件夹是相对于当前文件所在路径来说的来说的 # book.py在blueprint文件夹下,所以我在当前文件夹下创建一个名为666的文件夹 # 那么寻找模板就会到blueprint的666文件夹下寻找 book_app = Blueprint("book", __name__, template_folder="666") @book_app.route("/book/gone") def gone(): return render_template("satori.html")
模板文件寻找方式,会先到templates文件夹里面去找。如果没有,再去我们蓝图指定的文件夹里找。也就是说,如果我在templates文件里也定义了一个satori.html,那么会找templates的satori.html。
7.蓝图中静态文件寻找规则
和模板一样,flask默认会在主项目的static文件里面去寻找
如果我在blueprint里面定义了一个bl_static,我们才能让模板找到这里的css呢?
h2{ color: aquamarine; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% url_for('book.static', filename='1.css') %}"> </head> <body> <h2>我是主目录templates里的html文件,但是我要找蓝图里面的css</h2> </body> </html>
from flask import Blueprint, render_template # 这里指定了static_folder="bl_static",那么这个静态文件查找就是相对于当前文件所在路径的bl_static # 但是我们flask在查找的时候默认是当前主项目的static,也就是和templates同目录的static # 所以我们在html模板中指定的是,url_for('book.bl_static',filename='1.css')而不是url_for('bl_static',filename='1.css') # 由于我们指定了book.bl_static,那么flask就会找到我们的蓝图book,而我们在book.py中定义了static_folder # 那么flask就会去我们在book.py中指定的static_folder去找静态文件。如果不加book,那么还是会去项目的static文件夹去找 # 并且我想说的是,即便我们指定了蓝图,也和模板一样,默认到当前主项目的静态目录去找,找不到再去蓝图指定的静态目录里去找 # 如果这里定义的是static不是bl_static的话,那么是找不到的。 # 因为我们主程序的static_folder就是static,因此如果两者名字一样,就不会再来蓝图指定的静态目录里面找了 # 因此不要将主项目的静态目录和蓝图里的静态目录写成一样的 book_app = Blueprint("book", __name__, template_folder="666", static_folder="bl_static") @book_app.route("/book/gone") def gone(): return render_template("1.html")
8.url_for翻转蓝图注意事项
如果我想获取蓝图中的url怎么办呢?
老规矩,我想在start.py中获取gone的url,如果两个方法都在主程序中,毫无疑问一个url_for("gone")就搞定了,但是现在其中一个方法在蓝图中,还可以这样吗?我们来试一下
from flask import Flask, url_for # 将app导入进来 from blueprint.movie import movie_app from blueprint.book import book_app app = Flask(__name__) # 然后进行注册 app.register_blueprint(movie_app) app.register_blueprint(book_app) @app.route('/get') def get(): return url_for("gone") if __name__ == '__main__': app.run(port=8888, debug=True)
因此需要指定蓝图
@app.route('/get') def get(): return url_for("book.gone")
同理我们在模板中使用url_for也需要指定蓝图,url_for在模板和py文件中的使用方法是一样的。并且即使在同一个蓝图,要反响解析url,也需要指定蓝图
9.子域名实现详解
我新建了一个cms.py
from flask import Blueprint # 指定了一个subdomain,那么以后就可以通过子域名访问,即cms. cms_bp = Blueprint("cms", __name__, subdomain="cms") # 这里的/index,我们是通过localhost:port/index访问 # 那么以后就可以使用cms.localhost:port/index访问,当然还要隐藏问题,我们会说 @cms_bp.route('/index') def index(): return "欢迎欢迎,热烈欢迎"
from flask import Flask, url_for # 将app导入进来 from blueprint.movie import movie_app from blueprint.book import book_app from blueprint.cms import cms_bp app = Flask(__name__) # 然后进行注册 app.register_blueprint(movie_app) app.register_blueprint(book_app) app.register_blueprint(cms_bp) # 如果现在执行的话,那么理论上要通过cms.localhost:8888或者cms.127.0.0.1:8888/index访问 # 但是不可以,因为ip地址是不可以有子域名的,所以我们需要配置一下。就像我们购买域名,然后映射到我们服务器的ip地址上 # 所有和配置相关的都放在app.config这个字典下面 # 我们这里是测试,所以就直接使用本地就可以,我们希望在访问京东的时候能够访问到我们本地 # 所以我们还需要都hosts文件里面配置一下 ''' 127.0.0.1 jd.com 127.0.0.1 cms.jd.com ''' # 那么以后在访问jd.com:8888,就会访问我们本机 app.config["SERVER_NAME"] = 'jd.com:8888' @app.route('/index') def index(): return "欢迎,热烈欢迎" if __name__ == '__main__': app.run(host="localhost", port=8888, debug=True)
3.flask视图进阶的更多相关文章
- Flask视图函数报fmalformed url rule错误的原因
Flask视图函数报fmalformed url rule错误,原因可能是包含中文字符了 把标点符号都重新写一遍英文格式的,可能就不会报这个了
- Django 2.0 学习(07):Django 视图(进阶-续)
接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...
- Flask 视图
写个验证用户登录的装饰器:在调用函数前,先检查session里有没有用户 from functools import wraps from flask import session, abort de ...
- flask 视图函数的使用
flask框架 视图函数当中 各种实用情况简单配置 1 建立连接 2 路由参数 3 返回网络状态码 4 自定义错误页面 5 重定向 6 正则url限制 和 url 优化 7 设置和获取cookie # ...
- Flask 视图,中间件
视图 FBV def index(nid): """ 请求相关信息 request.method # 请求方式 request.args # get 方式的参数获取 re ...
- flask 电子邮件进阶实践-用模板发送163邮件
电子邮件进阶实践 下面来学习构建邮件的HTML正文,并使用模板组织内容. 一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html).处于全面的考虑,一封 ...
- Flask视图函数与普通函数的区别,响应对象Response
视图函数与普通函数看似没什么区别,其实他们的返回值上有着很大的区别. from flask import Flask app = Flask(__name__) @app.route('/hello' ...
- Flask 视图,模板,蓝图.
https://www.cnblogs.com/wupeiqi/articles/7552008.html 1. 配置文件 from flask import Flask app =Flask(__n ...
- Flask视图函数与模板语法
1.Django中的CBV模式 2.Flask中的CBV和FBV def auth(func): def inner(*args, **kwargs): result = ...
随机推荐
- 拉普拉斯矩阵(Laplacian Matrix) 及半正定性证明
摘自 https://blog.csdn.net/beiyangdashu/article/details/49300479 和 https://en.wikipedia.org/wiki/Lapla ...
- POJ 1015 Jury Compromise (动态规划)
dp[i][j]代表选了i个人,D(J)-P(J)的值为j的状态下,D(J)+P(J)的最大和. #include <cstdio> #include <cstring> #i ...
- C++的几种字符类型
我们在C学过了char字符类型. 在C++中,char是基本的字符类型,但却不仅仅有这一种字符类型! 类型 含义 该类型数据所占的最小比特位数 char 字符 8位(即可表示28个字符) wchar_ ...
- 微信小程序-腾讯地图显示偏差问题
原文地址: http://fanjiajia.cn/2018/08/30/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F-%E8%85%BE%E8%AE%A ...
- TextView AutoLink, ClikSpan 与长按事件冲突的解决
前言 首先,我们先来复习一下 autoLink 和 ClickableSpan 是干什么用的. autoLink 当中有五个属性值:分别是 phone.email.map.web.all 和 none ...
- [poj] 2396 [zoj] 1994 budget || 有源汇的上下界可行流
poj原题 zoj原题 //注意zoj最后一行不要多输出空行 现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出.列代表不同赛区支出的矩阵.组委会曾经开会讨论过各类支出的总和,以及各赛区 ...
- [Leetcode] Remove duplicates from sorted array ii 从已排序的数组中删除重复元素
Follow up for "Remove Duplicates":What if duplicates are allowed at most twice? For exampl ...
- MySQL之数据库及表的修改和删除
本文章来自实验楼的操作过程和其中相应地解释.(博客园不知道怎么回事,上传图片总是失败.) 一.对数据库修改 1)删除数据库的命令为:DROP DATABASE 数据名; 二.对表的修改 1)重命名一张 ...
- BZOJ 3629 JLOI2014 聪明的燕姿 约数和+DFS
根据约数和公式来拆s,最后再把答案乘出来,我们发先这样的话递归层数不会太大每层枚举次数也不会太多,然而我们再来个剪枝就好了 #include<cstdio> #include<ios ...
- Codeforces Round #520 (Div. 2) B. Math
B. Math time limit per test:1 second memory limit per test:256 megabytes Description: JATC's math te ...