flask之路由詳解


一、路由的本質

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.routeapp.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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM