Python的Flask架構中@app.route的用法教程_python

來源:互聯網
上載者:User

在我上一篇文章,我搭了一個架構,類比了Flask網站上“@app.route(‘/')”第一條例子的行為。

如果你錯過了那篇“這不是魔法”,請點擊這裡。

在這篇文章中,我們打算稍微調高點難度,為我們的URL加入可變參數的能力,在本文的最後,我們將支援下述程式碼片段所期望達到的行為。

 app = Flask(__name__) @app.route("/hello/<username>")def hello_user(username):  return "Hello {}!".format(username)

這樣下面的路徑執行個體(path):
/hello/ains
將會匹配上面的路徑,給我們的輸出為
Hello ains!

以正則的形式表達我們的路徑。

現在我們將允許我們的URL動態變化,我們不再能夠將用先前使用“@app.route()”註冊的路徑直接與路徑執行個體比較。

我們將用什麼替代?我們需要用上Regex,這樣我們就可以將路徑作為一種模式進行匹配,而不和一條固定的字串比較了。

我不打算在本文展開討論Regex的細節,不過如果你需要一份複習資料,可以點擊這個網站。

那麼,我們的第一步是將我們的路徑轉化成Regex模式,這樣我們就能在輸入路徑執行個體時進行匹配。我們也將使用這個Regex提取我們感興趣的變數。

那麼,匹配路徑”/hello/”的Regex該長啥樣呢?

嗯一個簡單的Regex譬如“^/hello/(.+)$”將是個好的開始,讓我們一起看看它和代碼是怎麼一起工作的:

 import re route_regex = re.compile(r"^/hello/(.+)$")match = route_regex.match("/hello/ains") print match.groups()

將會輸出:
('ains',)

不錯,不過,理想情況是我們想要維護我們已經匹配上的第一組連結,並且從路徑“/hello/”識別出“username”。

命名擷取的群組

幸運的是,Regex也支援命名擷取的群組,允許我們給匹配組分配一個名字,我們能在讀取我們的匹配之後找回它。

我們可以使用下述符號,給出第一個例子識別“username”的擷取的群組。
 

/hello/(<?P<username>.+)"

然後我們可以對我們的Regex使用groupdict()方法,將所有擷取的群組當作一個字典,組的名字對應匹配上的值。

那麼我們給出下述代碼:
 

route_regex = re.compile(r'^/hello/(?P<username>.+)$')match = route_regex.match("/hello/ains") print match.groupdict()

將為我們輸出以下字典:
{'username': 'ains'}

現在,有了我們所需要的Regex的格式,以及如何使用它們去匹配輸入的URLs的知識,最後剩下的是寫一個方法,將我們聲明的路徑轉換成它們等價的Regex模式。

要做這個我們將使用另一個Regex(接下來將全是Regex),為了讓我們路徑中的變數轉換成正則表示式模式,那這裡作為示範我們將將“”轉換成“(?P.+)”。

聽起來太簡單了!我們將可以只用一行新代碼實現它。

 def build_route_pattern(route):  route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)  return re.compile("^{}$".format(route_regex)) print build_route_pattern('/hello/<username>')

這裡我們用一個Regex代表所有出現的模式(一個包含在角括弧中的字串),與它的Regex命名組等價。

re.sub的第一個參數 我們將我們的模式放進括弧,目的是把它分配到第一個匹配組。在我們的第二個參數,我們可以使用第一匹配組的內容,方法是寫1(2將是第二匹配組的內容,以此類推…….)

那麼最後,輸入模式
 

/hello/<username>

將給我們Regex:
 

^/hello/(?P<username>.+)$

推陳出新

讓我們掃一眼上次我們寫的簡單NotFlask類。
 

class NotFlask():  def __init__(self):    self.routes = {}   def route(self, route_str):    def decorator(f):      self.routes[route_str] = f      return f     return decorator   def serve(self, path):    view_function = self.routes.get(path)    if view_function:      return view_function()    else:      raise ValueError('Route "{}"" has not been registered'.format(path)) app = NotFlask() @app.route("/")def hello():  return "Hello World!"

現在我們有一個新的改進方法用來匹配輸入的路徑,我們打算移除我們上一版實現時用到的原生字典。

讓我們從改造我們的函數著手,以便於添加路徑,這樣我們就可以用(pattern, view_function)對列表代替字典儲存我們的路徑。

這意味著當一個程式員使用@app.route()裝飾一個函數,我們將要嘗試將他們的路徑編譯變成一個Regex,然後儲存它,屬於一個在我們新的路徑列表裡的裝飾函數。

讓我們看看實現代碼:

 class NotFlask():  def __init__(self):    self.routes = []   # Here's our build_route_pattern we made earlier  @staticmethod  def build_route_pattern(route):    route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)    return re.compile("^{}$".format(route_regex))   def route(self, route_str):    def decorator(f):      # Instead of inserting into a dictionary,      # We'll append the tuple to our route list      route_pattern = self.build_route_pattern(route_str)      self.routes.append((route_pattern, f))       return f     return decorator

我們也打算需要一個get_route_match方法,給它一個路徑執行個體,將會嘗試並找到一個匹配的view_function,或者返回None如果一個也找不到的話。

然而,如果找了到匹配的話,除了view_function之外,我們還需要返回一個東西,那就是我們包含之前捕獲匹配組的字典,我們需要它來為視圖函數傳遞正確的參數。

好了我們的get_route_match大概就長這樣:

 def get_route_match(path):  for route_pattern, view_function in self.routes:    m = route_pattern.match(path)    if m:      return m.groupdict(), view_function   return None

現在我們快要完成了,最後一步將是找出調用view_function的方法,使用來自Regex匹配組字典的正確參數。

調用一個函數的若干種方法

讓我們回顧一下不同的方法調用一個python的函數。

比如像這樣:

 def hello_user(username):  return "Hello {}!".format(username)

最簡單的(也許正是你所熟知的)辦法是使用正則參數,在這裡參數的順序匹配我們定義的那些函數的順序。

>>> hello_user("ains")Hello ains!

另一種方法調用一個函數是使用關鍵詞參數。關鍵詞參數可以通過任何順序指定,適合有許多選擇性參數的函數。

>>> hello_user(username="ains")Hello ains!

在Python中最後一種調用一個函數的方法是使用關鍵詞參數字典,字典中的關鍵詞對應參數名稱。我們告訴Python解包一個字典,並通過使用兩個星號“**”來把它當作函數的關鍵詞參數。 下面的程式碼片段與上面的程式碼片段完全一樣,現在我們使用字典參數,我們可以在運行時動態建立它。

>>> kwargs = {"username": "ains"}>>> hello_user(**kwargs)Hello ains!

好了,還記得上面的groupdict()方法?就是那個同樣的在Regex完成匹配後返回{“username”: “ains”}的傢伙?那麼現在我們瞭解了kwargs,我們能很容易向我們的view_function傳遞字典匹配,完成NotFlask!

那麼讓我們把這些都塞進我們最終的類中。
 

class NotFlask():  def __init__(self):    self.routes = []   @staticmethod  def build_route_pattern(route):    route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)    return re.compile("^{}$".format(route_regex))   def route(self, route_str):    def decorator(f):      route_pattern = self.build_route_pattern(route_str)      self.routes.append((route_pattern, f))       return f     return decorator   def get_route_match(self, path):    for route_pattern, view_function in self.routes:      m = route_pattern.match(path)      if m:        return m.groupdict(), view_function     return None   def serve(self, path):    route_match = self.get_route_match(path)    if route_match:      kwargs, view_function = route_match      return view_function(**kwargs)    else:      raise ValueError('Route "{}"" has not been registered'.format(path))

接下來,就是見證奇蹟的時刻,請看下面程式碼片段:

 app = NotFlask() @app.route("/hello/")def hello_user(username):return "Hello {}!".format(username) print app.serve("/hello/ains")

我們將得到輸出:

Hello ains!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.