<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ![關于視圖和路由的進階技巧](https://box.kancloud.cn/2016-04-15_57105525b5756.png) # 關于視圖和路由的進階技巧 ## 視圖裝飾器 Python裝飾器讓我們可以用其他函數包裝特定函數。 當一個函數被一個裝飾器"裝飾"時,那個裝飾器會被調用,接著會做額外的工作,修改變量,調用原來的那個函數。我們可以把我們想要重用的代碼作為裝飾器來包裝一系列視圖。 裝飾器的語法看上去像這樣: ```python @decorator_function def decorated(): pass ``` 如果你看過Flask入門指南,那么對這個語法應該不感到陌生。`@app.route`正是用于在Flask應用中給視圖函數設定路由URL的裝飾器。 讓我們看一下在你的Flask應用中用得上的一些別的裝飾器。 ### 認證 Flask-Login使得用戶認證系統的實現不再困難。 除了處理用戶認證的細節之外,Flask-Login允許我們使用`@login_required`這個裝飾器來驗證用戶對某些資源的訪問權限。 下面是從一個用到Flask-Login和`@login_required`裝飾器的一個示范應用中獲取的例子: ``` from flask import render_template from flask_login import login_required, current_user @app.route('/') def index(): return render_template("index.html") @app.route('/dashboard') @login_required def account(): return render_template("account.html") ``` > **注意** > `@app.route`必須是最外面的視圖裝飾器。 只有已經驗證的用戶能夠接觸到*/dashboard*路由。你可以配置Flask-Login來重定向未驗證用戶到登錄頁面,返回HTTP 401狀態碼或別的你樂意的事。 > **參見** > 通過[官方文檔](http://flask-login.readthedocs.org/en/latest/)可以讀到更多關于Flask-Login的內容 ### 緩存 意淫一下,假如你的應用突然有一天在微博/朋友圈或網上別的地方火了。 于是秒秒鐘會有成千上萬的請求涌向你的應用。你的主頁在每個請求中都要從數據庫跑上一大趟,結果海量的請求導致網站慢得像教務系統一樣。 你能做什么來加速這一過程,以免用戶以為你的應用掛掉了? 答案不止一個,不過就本章主旨而言,標準答案是實現緩存。 特別的,我們將要用到[Flask-Cache](http://pythonhosted.org/Flask-Cache/)拓展。這個拓展給我們提供一個可以用來緩存某個響應一段時間的裝飾器。 你可以將Flask-Cache配置成跟你想用的后臺緩存一起使用。一個普遍的選擇是[Redis](http://redis.io/),一個容易配置和使用的軟件。 假設Flask-Cache已經配置好了,下面是我們的被裝飾的視圖的例子: ``` from flask_cache import Cache from flask import Flask app = Flask() # 通過這個方式獲取相關配置 cache = Cache(app) @app.route('/') @cache.cached(timeout=60) def index(): [...] # 進行一些數據庫調用來獲取所需信息 return render_template( 'index.html', latest_posts=latest_posts, recent_users=recent_users, recent_photos=recent_photos ) ``` 現在這個函數將會在每60秒最多運行一次。響應的結果會被保存在緩存中,并可以讓期間的每一個請求獲取。 > **注意** > Flask-Cache同時允許我們**記住**函數 - 或緩存通過給定的參數調用的某個函數。你甚至可以緩存過于復雜的Jinja2模板片段! ### 自定義裝飾器 在這個例子中,讓我們假設我們有一個應用,每個月要求用戶定期付費。如果一個用戶的賬戶已經過期,我們要重定向他們到賬單頁面,并告知其悲傷的現實。 myapp/util.py ``` from functools import wraps from datetime import datetime from flask import flash, redirect, url_for from flask_login import current_user def check_expired(func): @wraps(func) def decorated_function(*args, **kwargs): if datetime.utcnow() > current_user.account_expires: flash("Your account has expired. Please update your billing information.") return redirect(url_for('account_billing')) return func(*args, **kwargs) return decorated_function ``` 1. 當用`@check_expired`裝飾一個函數時,`check_expired()`被調用,被裝飾的函數作為一個參數被傳遞進來。 2. `@wraps`是一個裝飾器,告知Python函數`decorated_function()`包裝了視圖函數`func()`。嚴格來說這不是必須的,但是這么做會使得裝飾函數更加自然一些,更有利于文檔和調試。 3. `decorated_function`將截取原本傳遞給視圖函數`func()`的args和kwargs。在這里我們檢查用戶的賬戶是否過期。如果是,我們將閃爍一則信息,并重定向到賬單頁面。 4. 既然已經處理好自己的事情,我們把原來的參數交由視圖函數`func()`去繼續執行。 位于最頂部的裝飾器將最先運行,然后調用下一個函數:一個視圖函數或下一個裝飾器。裝飾器語法只是一個語法糖而已。 ```python # 這樣 @foo @bar def one(): pass ``` ```python # 等同于這樣: def two(): pass two = foo(bar(two)) r2 = two() r1 == r2 # True ``` 下面這個例子用到了我們自定義的裝飾器和來自Flask-Cache拓展的`@login_required`裝飾器。我們可以將多個裝飾器堆成棧來一起使用。 myapp/views.py ``` from flask import render_template from flask_login import login_required from . import app from .util import check_expired @app.route('/use_app') @login_required @check_expired def use_app(): """歡迎光臨""" return render_template('use_app.html') @app.route('/account/billing') @login_required def account_billing(): """拿賬單來""" # [...] return render_template('account/billing.html') ``` 當一個用戶試圖訪問*/use\_app*時,`check_expired()`將在執行視圖函數之前確保相關的賬戶資料不會泄漏。 > 參見 > 在Python文檔中可以讀到更多關于`wraps()`的內容:<http://docs.python.org/2/library/functools.html#functools.wraps> ## URL轉換器 ### 內建轉換器 當你在Flask中定義一個路由時,你可以將指定的一部分轉換成Python變量并傳遞給視圖函數。 ``` @app.route('/user/<username>') def profile(username): pass ``` 在URL中作為<username>的那一部分內容將作為`username`參數傳遞給視圖函數。你也可以指定一個轉換器過濾出特定的類型。 ``` @app.route('/user/id/<int:user_id>') def profile(user_id): pass ``` 在這個代碼塊中,<http://myapp.com/user/id/tomato> 這個URL會返回一個404狀態碼 -- 此物無處覓。 這是因為URL中預期是整數的部分卻遇到了一串字符串。 我們可以有另外一個接受一個字符串的視圖函數。*/usr/id/tomato/*將調用它,而前一個函數只會被*/user/id/124*所調用。 下面是來自Flask文檔的關于默認轉換器的表格: | 類型 | 作用 | | -------|------------------------------- | | string | 接受任何沒有斜杠`/`的文本(默認)| | int | 接受整數 | | float | 類似于`int`,但是接受的是浮點數 | | path | 類似于`string`,但是接受斜杠`/` | ### 自定義轉換器 我們也可以按照自己的需求打造自定義的轉換器。 Reddit - 一個知名的鏈接分享網站 - 用戶在此可以創建和管理基于主題和鏈接分享的社區。 比如`/r/python`和`/r/flask`,分別由URL`reddit.com/r/python`和`reddit.com/r/flask`表示。 Reddit有一個有趣的特性是,通過在URL中用一個`+`隔開各個社區名,你可以同時看到來自多個社區的帖子。比如`reddit.com/r/python+flask`。 我們可以使用一個自定義轉換器來實現這種特性。 我們可以接受由加號隔離開來的任意數目參數,通過我們的ListConverter轉換成一個列表,并傳遞給視圖函數。 util.py ```python from werkzeug.routing import BaseConverter class ListConverter(BaseConverter): def to_python(self, value): return value.split('+') def to_url(self, values): return '+'.join(BaseConverter.to_url(value) for value in values) ``` 我們需要定義兩個方法:`to_python()`和`to_url()`。 一如其名,`to_python()`用于轉換路徑成一個Python對象,并傳遞給視圖函數。而`to_url()`被`url_for()`調用,來轉換參數成為符合URL的形式。 為了使用我們的ListConverter,我們首先得將它的存在告知Flask。 /myapp/\_\_init\_\_.py ``` from flask import Flask app = Flask(__name__) from .util import ListConverter app.url_map.converters['list'] = ListConverter ``` > **注意** > 假如你的util模塊有一行`from . import app`,那么有可能陷入循環import的問題。這就是為什么我等到app初始化之后才import ListConverter。 現在我們可以一如使用內建轉換器一樣使用我們的轉換器。我們在字典中指定它的鍵為"list",所以我們可以在`@app.route()`中這樣使用: views.py ```python from . import app @app.route('/r/<list:subreddits>') def subreddit_home(subreddits): """顯示給定subreddits里的所有帖子""" posts = [] for subreddit in subreddits: posts.extend(subreddit.posts) return render_template('/r/index.html', posts=posts) ``` 這應該會像Reddit的子社區系統一樣工作。這樣的方法可以用來實現你能想到的URL轉換器。 ## 總結 * Custom URL converters can be a great way to implement creative features involving URL’s. * 來自Flask-Login的`@login_required`裝飾器可以幫助你限制驗證用戶對視圖的訪問。 * Flask-Cache插件為你提供一組裝飾器來實現多種方式的緩存。 * 我們可以開發自定義視圖裝飾器來幫助我們組織自己的代碼,并堅守DRY(Don't Repeat Yourself 不重復你自己)原則。 * 自定義的URL轉換器將會讓你很嗨地玩轉URL。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看