Flask URL默認轉換器、自定義轉換器、to_python、to_url

  • 2019 年 11 月 13 日
  • 筆記

Flask框架自帶的轉換器類型

  • int轉換器 <int:param> :接收整數
  • float轉換器 <float:param>: 接收浮點數
  • string轉換器 <string:param>: 接收string類型(默認則是string轉換器
  • path轉換器 <path:param>:和默認的相似,但也接收斜線

設置int類型的路徑參數

# 轉換器 <int:goods_id>  @app.route('/goods_info/<int:goods_id>')  def goods_info(goods_id):      return "goods_id is %d" % goods_id

測試訪問 http://127.0.0.1:5000/goods_info/123

設置float轉換器的路徑參數

# 設置float轉換器  @app.route('/goods_info/<float:goods_id>')  def goods_info(goods_id):      return "goods_id is %s" % goods_id

可以發現參數為float參數是能夠正常訪問處理的。

當傳遞參數為 123 整數的時候,則報錯Not Found

當傳遞參數為 hello 字符串的時候,則報錯Not Found

設置string類型的路徑參數

# 設置轉換器 <string:goods_id>  @app.route('/goods_info/<string:goods_id>')  def goods_info(goods_id):      return "goods_id is %s" % goods_id

測試訪問 http://127.0.0.1:5000/goods_info/你好

可以看到中文的字符串參數也是可以直接獲取的。

  • 其中如果轉換器不寫類型,默認就是string類型的,示例如下:
# 設置轉換器 默認是string  @app.route('/goods_info/<goods_id>')  def goods_info(goods_id):      return "goods_id is %s" % goods_id

設置path轉換器的路徑參數

# 設置path轉換器  @app.route('/goods_info/<path:goods_id>')  def goods_info(goods_id):      return "goods_id is %s" % goods_id

測試訪問:http://127.0.0.1:5000/goods_info/hello//world/123

可以看到 path轉換器 可以接收斜杠 / 將後面所有的字符串都作為參數傳遞。

上面的這幾種Flask自帶的轉換器雖然可以設置很多參數了,但是還是無法匹配一些特殊需求的路徑參數。

例如:在發送短訊的URL中,路徑參數設置為手機號碼,上面的自帶類型就無法精確匹配手機號碼了。

這時候就需要自定義路由轉換器出場了。

自定義路由轉換器

1.自定義路由轉換器的基礎類:

from werkzeug.routing import BaseConverter

2.創建自定義轉換器,以及將轉換器加入Flask應用中:

# 創建自定義轉換器  # 1. 定義自己的轉換器  class RegexConverter(BaseConverter):      """"""      def __init__(self, url_map, regex):          """          :param url_map: 固定傳遞的參數,用於調用父類的初始化方法          :param regex: 從url使用()傳遞過來的正則參數          """          # 調用父類的初始化方法          super(RegexConverter, self).__init__(url_map)          # 將正則表達式的參數保存到對象的屬性中,flask會去使用這個屬性來進行路由的正則匹配          self.regex = regex    # 2. 將自定義的轉換器添加到flask的應用中  app.url_map.converters["re"] = RegexConverter

3.在視圖函數中設置自定義路由轉換器re:

# 127.0.0.1:5000/send/18912345678  # <re(r''): param> 使用re自定義轉換器,其中()則是需要傳遞的參數  @app.route("/send/<re(r'1[34578]d{9}'):mobile_num>")  def send_sms(mobile_num):      return "send sms to %s" % mobile_num

4.測試訪問符合正則匹配的電話號碼的url

訪問 http://127.0.0.1:5000/send/18912345678

5.測試訪問不符合正則匹配的url

訪問 http://127.0.0.1:5000/send/189123

根據不符合正則匹配的URL參數,則報錯Not Found。從效果來看,就可以知道通過這個自定義的轉換器,我們可以實現這種特殊的參數獲取。

創建專屬手機號碼的轉換器

上面的轉換器可以傳遞正則匹配的規則,屬於一種萬能轉換器,下面將其創建一個專屬手機號碼的轉換器。

# 創建Moblie的專屬轉換器  class MobileConverter(BaseConverter):        def __init__(self,url_map):          # super(MobileConverter,self).__init__(url_map) # 調用父類方法一          super().__init__(url_map) # 調用父類方法二          self.regex = r'1[34578]d{9}'    # 註冊MobileConverter轉換器  app.url_map.converters["mobile"] = MobileConverter    # 設置視圖函數  @app.route("/send/<mobile:mobile_num>")  def send_sms(mobile_num):      return "send sms to %s" % mobile_num

其實這個例子主要是想說明Flask可以創建多個自定義轉換器。

另外,在Django中有中間類這個類方法來處理url請求至視圖函數之間的業務處理,例如:權限驗證,session數據記錄等等。

在Flask中可以使用專屬轉換器的to_pythonto_url兩個函數來實現類似中間類這樣的功能。

下面來看看。

查看BaseConverter類中的源碼

class BaseConverter(object):      """Base class for all converters."""        regex = "[^/]+"      weight = 100        def __init__(self, map):          self.map = map        def to_python(self, value):          return value        def to_url(self, value):          if isinstance(value, (bytes, bytearray)):              return _fast_url_quote(value)          return _fast_url_quote(text_type(value).encode(self.map.charset))

首先從源碼來分析一下這個繼承類中to_pythonto_url函數。

  • to_python 將url傳遞的參數,直接將其傳遞至視圖函數之中
  • to_url 則是當另一個視圖函數使用 url_for() 這個方法跳至該轉換器的時候,會將url的參數傳遞到url路徑的參數中。

單單這麼解釋有些抽象,下面來看看示例。

to_python 函數

# 創建Moblie的專屬轉換器  class MobileConverter(BaseConverter):        def __init__(self,url_map):          # super(MobileConverter,self).__init__(url_map)          super().__init__(url_map)          self.regex = r'1[34578]d{9}'        def to_python(self, value):          """"""          print("to_python方法被調用")          # value是在路徑進行正則表達式匹配的時候提取的參數          return "abc" # 該value會傳遞到視圖函數中    app.url_map.converters["mobile"] = MobileConverter    @app.route("/send/<mobile:mobile_num>")  def send_sms(mobile_num):      return "send sms to %s" % mobile_num

此時測試訪問 http://127.0.0.1:5000/send/18912345678

按照原來訪問後在瀏覽器會打印 send sms to 18912345678 的信息,但是由於to_python 設置返回是 "abc",所以瀏覽器將會打印 send sms to abc,下面來瀏覽器執行驗證看看,如下:

從瀏覽器就可以判斷出to_python方法就是url傳遞到視圖函數中間的業務處理方法,其實就相當於Django的中間類。

如果有權限驗證類的需求,可以在to_python中實現。

to_url 函數

# 創建Moblie的專屬轉換器  class MobileConverter(BaseConverter):        def __init__(self,url_map):          # super(MobileConverter,self).__init__(url_map)          super().__init__(url_map)          self.regex = r'1[34578]d{9}'        def to_python(self, value):          """"""          print("to_python方法被調用")          # value是在路徑進行正則表達式匹配的時候提取的參數          return value # 該value會傳遞到視圖函數中        def to_url(self, value):          """使用url_for的方法的時候被調用"""          print("to_url方法被調用")          return "15811111111" # 該value會修改url路徑中的參數為 15811111111    app.url_map.converters["mobile"] = MobileConverter    @app.route("/send/<mobile:mobile_num>")  def send_sms(mobile_num):      return "send sms to %s" % mobile_num    @app.route("/hello_send")  def hello_send():      return redirect(url_for('send_sms', mobile_num=18612345678))

這個示例是首先訪問 hello_send 視圖函數,然後使用 url_for函數跳轉至 send_sms 視圖函數。

在這種過程中,hello_send 視圖函數跳轉的時候設置的路徑參數為 mobile_num=18612345678

那麼正常在瀏覽器轉發後的url訪問應該是:http://127.0.0.1:5000/send/18612345678

但是由於to_url返回的是15811111111,所以最終跳轉的url顯示會是 http://127.0.0.1:5000/send/15811111111

下面來確認看看,訪問http://127.0.0.1:5000/hello_send

可以從圖中的傳遞說明,應該基本上都可以看出參數的傳遞過程。