一、路由的本质
flask的路由直接在函数上使用装饰器的话非常的乱,那可不可以想django一样把路由都写到一起呢。
查看源码,我们知道原来的路由就是一个装饰器,装饰器的第一个参数就是路由规则
实际上在装饰器内的闭包函数最终调用的是def add_url_rule(self,rule,endpoint=None,view_func=None,provide_automatic_options=None,**options):
''' rule:路由规则 endpoint:反向解析别名,和CBV中as_view(name=...)的name是一样的。因为在源码内部,实际上也会去取参数view_func的__name__也就是指定的函数或类的名字 view_func:响应对象 '''
因此我们可以直接改写路由。
将原来装饰器修饰的路由,改写为使用add_url_rule
的路由
from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "ok" if __name__ == '__main__': app.run()
改写为
from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "ok" # 路由匹配规则和响应函数 app.add_url_rule("/index", view_func=index) if __name__ == '__main__': app.run()
二、CBV
和django一样,flask也是有CBV的,都是通过as_view()来返回view对象,通过匹配然后执行view函数完成dispatch_request的响应方式的分发。
不同的是。as_view()中必须传递一个name,这个name就是作为反向解析的名字给类的__name__
flask导入的views.View类必须实现dispatch_request方法,不然匹配路由成功后执行view函数完成分发会报错。因为源码中必须让你实现
from flask import Flask,views app = Flask(__name__) #简单模式 class IndexView(views.View): def dispatch_request(self): print('Index') return 'Index!' app.add_url_rule('/index1', view_func=IndexView.as_view(name='index1')) # name=endpoint 反向解析的别名 if __name__ == '__main__': app.run()
2.1 使用views.MethodView类
这个类已经帮我们实现好了dispatch_request
方法,就不需要自己再去写了。而他帮你实现的dispatch_request
方法中做的事和Django中的dispath方法中做的事情是一致的。都是通过反射去取响应的请求方式名同名的函数
from flask import Flask,views app = Flask(__name__) #通常用此方式 class IndexView(views.MethodView): def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint if __name__ == '__main__': app.run()
2.2 指定响应的请求方式类型
无论是FBV还是CBV的实现方式都可以在函数内部或类内部添加methods = ['GET',"POST"]
.当app.add_url_rule
执行时会通过反射去函数或类内部的methods
中取指定的响应方法,如果没有写,默认只响应get方式请求。
但如果是CBV的方式,没有写methods
则和django一样去取类内部实现的方法。但如果写了methods
,只会响应methods
中的请求方式对应的方法
'''CBV''' from flask import Flask,views app = Flask(__name__) class IndexView(views.MethodView): methods = ['GET'] # 只响应GET请求对于的get方法 def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) if __name__ == '__main__': app.run()
2.3 指定装饰器修饰
在使用CBV,添加对应的路由是需要通过as_view来得到view对象。而在as_view()内部,会根据类属性decorators=[auth, ]
来执行[]中对应的装饰器。也就是说,当程序执行时,进入as_view()后,会给该装饰器传入一个view对象,然后进入对应的装饰器,该装饰器必须返回一个view对象,否则就会报错。
传进去一个view,返回一个同名的view对象,这不就是装饰器嘛。给view加了一层装饰器,无论哪个路由匹配成功,都会先进入该装饰器。
from flask import Flask,views,url_for,jsonify,render_template app = Flask(__name__) def auth(view): def inner(*args,**kwargs): if view.__name__=="index": res = view(*args,**kwargs) else: # res = render_template("404.html") res = jsonify({"status": 0,"msg":"傻逼"}) return res return inner #通常用此方式 class IndexView(views.MethodView): # 给dispatch_request加装饰器 decorators = [auth, ] def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index', view_func=IndexView.as_view(name='index1')) if __name__ == '__main__': app.run()
三、路由参数
@app.route
和app.add_url_rule
参数:
''' rule:路由规则 endpoint:反向解析别名,和CBV中as_view(name=...)的name是一样的。因为在源码内部,实际上也会去取参数view_func的__name__也就是指定的函数或类的名字 view_func:响应对象 defaults:默认值为None, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'} methods:允许的请求方式,如:["GET", "POST"] strict_slashes: 对URL最后的 / 符号是否严格要求,默认等于None redirect_to: 重定向到指定地址 '''
- url_for: 可以根据反向解析的别名来拿到对应路由
from flask import Flask,views,url_for app = Flask(__name__) @app.route("/index/",endpoint="a",methods=["POST","GET"],strict_slashes=None,redirect_to="/index2") def index(): return "ok" @app.route("/index2") def index2(): # 打印反向解析的别名是a的路由 print(url_for("a")) return "吃饭去了" if __name__ == '__main__': app.run()
四、路由转换器
路由转化器,其实就是django中路由的有名分组,通过参数名来得到路由的参数。区别是不用正则,但是可以指定参数类型。
from flask import Flask app = Flask(__name__) # 和有名分组一样,只不过不用正则了 @app.route("/<string:flag>") def index(flag): return f"jason is sb ? {flag}" if __name__ == '__main__': app.run()
默认路由转化器参数类型
DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
4.1 自定义转换器
- 1 写类,继承BaseConverter,实现三个方法init、to_python、to_url
- 2 注册:
app.url_map.converters['regex'] = RegexConverter
- 3 使用:
@app.route('/index/<regex("\d+"):nid>')
正则表达式会当作第二个参数传递到类中
#1 写类,继承BaseConverter,实现三个方法init、to_python、to_url #2 注册:app.url_map.converters['regex'] = RegexConverter #3 使用:@app.route('/index/<regex("\d+"):nid>') 正则表达式会当作第二个参数传递到类中 from flask import Flask, views, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) class RegexConverter(BaseConverter): """ 自定义URL匹配正则表达式 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 """ return int(value)+123 def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 """ # 先执行父类方法 val = super(RegexConverter, self).to_url(value) return val+"json" # 添加到flask中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("\d+"):nid>') def index(nid): print(nid) print(url_for('index', nid='888')) # 使用反向解析,会执行自定义转换器的to_url return 'Index' if __name__ == '__main__': app.run()
来源:https://www.cnblogs.com/XuChengNotes/p/12149300.html