<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Werkzeug 教程 歡迎來到 Werkzeug 教程,我們將會實現一個類似 [TinyURL](http://tinyurl.com/) 的網站來儲存 URLS。我們將會使用的庫有模板引擎 [Jinja](http://jinja.pocoo.org/) 2,數據層支持 [redis](http://redis.io/) ,當然還有 WSGI 協議層 Werkzeug。 你可以使用 pip 來安裝依賴庫: ~~~ pip install Jinja2 redis ~~~ 同時確定你的本地開啟一個 redis 服務,如果你是OS X系統,你可以使用 brew 來安裝 redis: ~~~ brew install redis ~~~ 如果你是用 Ubuntu 或 Debian, 你可以使用 apt-get: ~~~ sudo apt-get install redis ~~~ Redis 專為 UNIX 系統開發,并沒有考慮為 Windows 設計。但對于開發來說,非官方的版本已經足夠了,你可以從 [github](https://github.com/dmajkic/redis/downloads) 得到它。 [TOC=2,3] ### 簡短介紹 在這個教程中,我們將一起用 Werkzeug 創建一個短網址服務。請注意,Werkzeug 并不是一個框架,它是一個 WSGI 工具集的庫,你可以通過它來創建你自己的框架或 Web 應用。Werkzeug 是非常靈活的,這篇教程用到的一些方法只是 Werkzeug 的一部分。 在數據層,為了保持簡單,我們使用 [redis](http://redis.io/) 來代替關系型數據庫,而且 [redis](http://redis.io/) 也擅長來做這些。 最終的結果將會看起來像這樣: ![a screenshot of shortly](https://box.kancloud.cn/2015-10-16_56206f26bc58d.png) ### Step 0: WSGI 基礎介紹 Werkzeug 是一個 WSGI 工具包。WSGI 是一個 Web 應用和服務器通信的協議,Web 應用可以通過 WSGI 一起工作。 一個基本的 “Hello World” WSGI 應用看起來是這樣的: ~~~ def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello World!'] ~~~ 用過 WSGI 應用可以和環境通信,他有一個可調用的 start_response 。環境包含了所有進來的信息。 start_response 用來表明已經收到一個響應。通過 Werkzeug 你可以不必直接處理請求或者響應這些底層的東西,它已經為你封裝好了這些。 請求數據需要環境對象,Werkzeug 允許你以一個輕松的方式訪問數據。響應對象是一個 WSGI應用,提供了更好的方法來創建響應。 下面教你怎么用響應對象來寫一個應用: ~~~ from werkzeug.wrappers import Response def application(environ, start_response): response = Response('Hello World!', mimetype='text/plain') return response(environ, start_response) ~~~ 這里有一個在 URL 中查詢字符串的擴展版本(重點是 URL 中的 name 將會替代World): ~~~ from werkzeug.wrappers import Request, Response def applicatio n(environ, start_response): request = Request(environ) text = 'Hello %s!' % request.args.get('name', 'World') response = Response(text, mimetype='text/plain') return response(environ, start_response) ~~~ 到此為止,你已經足夠了解 WSGI 了。 ### Step 1: 創建目錄 在開始之前,首先為應用創建一個目錄: ~~~ /shortly /static /templates ~~~ 這個簡潔的目錄不是一個python包,他用來存放我們的項目文件。我們的入口模塊將會放在 /shortly目錄的根目錄下。 /static 目錄用來放置CSS、Javascript等靜態文件,用戶可以通過HTTP協議直接訪問。 /templates 目錄用來存放 Jinja2 模板文件,接下來你為項目創建的模板文件將要放到這個文件夾內。 ### Step 2: 基本結構 現在我們正式開始為我們的項目創建模塊。在 shortly 目錄創建 shortly.py 文件。首先來導入一些東西。為了防止混淆,我把所有的入口放在這,即使他們不會立即使用: ~~~ import os import redis import urlparse from werkzeug.wrappers import Request, Response from werkzeug.routing import Map, Rule from werkzeug.exceptions import HTTPException, NotFound from werkzeug.wsgi import SharedDataMiddleware from werkzeug.utils import redirect from jinja2 import Environment, FileSystemLoader ~~~ 接下來我們來為我們的應用創建基本的結構,并通過一個函數來創建應用實例,通過 WSGI中間件輸出 static 目錄的文件: ~~~ class Shortly(object): def __init__(self, config): self.redis = redis.Redis(config['redis_host'], config['redis_port']) def dispatch_request(self, request): return Response('Hello World!') def wsgi_app(self, environ, start_response): request = Request(environ) response = self.dispatch_request(request) return response(environ, start_response) def __call__(self, environ, start_response): return self. wsgi_app(environ, start_response) def create_app(redis_host='localhost', redis_port=6379, with_static=True): app = Shortly({ 'redis_host': redis_host, 'redis_port': redis_port }) if with_static: app.wsgi_app = SharedDataMiddleware(app.wsgi_app, { '/static': os.path.join(os.path.dirname(__file__), 'static') }) return app ~~~ 最后我們添加一部分代碼來開啟一個本地服務器,自動加載代碼并開啟調試器: ~~~ if __name__ == '__main__': from werkzeug.serving import run_simple app = create_app() run_simple('127.0.0.1', 5000, app, use_debugger=True, use_reloader=True) ~~~ 思路很簡單,我們的 Shortly 是一個實際的 WSGI 應用。 __call__ 方法直接調用 wsgi_app 。這樣做我們可以裝飾 wsgi_app 調用中間件,就像我們在 create_app函數中做的一樣。 wsgi_app 實際上創建了一個 Request 對象,之后通過dispatch_request 調用 Request 對象然后給 WSGI 應用返回一個 Response對象。正如你看到的:無論是創建 Shortly 類,還是還是創建 Werkzeug Request 對象來執行 WSGI 接口。最終結果只是從 dispatch_request 方法返回另一個 WSGI 應用。 create_app 可以被用于創建一個新的應用實例。他不僅可以通過參數配置應用,還可以選擇性的添加中間件來輸出靜態文件。通過這種方法我們甚至可以不配置服務器就能訪問靜態文件,這對開發是很有幫助的。 ### 插曲: 運行應用程序 現在你應該可以通過 python 執行這個文件了,看看你本機的服務: ~~~ $ python shortly.py * Running on http://127.0.0.1:5000/ * Restarting with reloader: stat() polling ~~~ 它告訴你自動加載已經開啟,他會通過各種各樣的技術來判斷硬盤上的文件是否改變來自動重啟。 在瀏覽器輸入這個URL,你將會看到 “Hello World!”。 ### Step 3: 環境 現在我們已經有了一個應用的基本類,可以通過構造函數來實現一些功能。通過構造函數我們可以渲染模板、連接redis。現在讓我們擴展這個類: ~~~ def __init__(self, config): self.redis = redis.Redis(config['redis_host'], config['redis_port']) template_path = os.path.join(os.path.dirname(__file__), 'templates') self.jinja_env = Environment(loader=FileSystemLoader(template_path), autoescape=True) def render_template(self, template_name, **context): t = self.jinja_env.get_template(template_name) return Response(t.render(context), mimetype='text/html') ~~~ ### Step 4: 路由 下一步是路由。我們可以通過路由來匹配和解析URL。Werkzeug 提供了一個靈活的集成路由。你需要創建一個 Map 實例并添加一系列 Rule對象。每個 rule 將會匹配 URL 并添加一個 “endpoint”。endpoint 通常是一個用于標記URL 的字符串。此外我們還可以使用它來翻轉 URL,但這不是這篇教程我們要做的。 把下列代碼放入構造函數: ~~~ self.url_map = Map([ Rule('/', endpoint='new_url'), Rule('/<short_id>', endpoint='follow_short_link'), Rule('/<short_id>+', endpoint='short_link_details') ]) ~~~ 現在我們創造了一個包含三個 URL 規則的字典。第一個規則, / 是根 URL 空間,我們可以調用一個邏輯函數來創建一個新 URL;第二個規則,根據規則指向一個目標URL;最后一個規則,和第二個有相同的規則,但是它在最后添加一個(+)來顯示鏈接鏈接詳細信息。 那么 endpoint 是怎么指向一個函數的?這是需要你解決的。本篇教程中是通過類中 on_+ endpoint 方法。具體如下: ~~~ def dispatch_request(self, request): adapter = self.url_map.bind_to_environ(request.environ) try: endpoint, values = adapter.match() return getattr(self, 'on_' + endpoint)(request, **values) except HTTPException, e: return e ~~~ 我們將 RUL 綁定到目前的環境返回一個 URLAdapter 。適配器可以用于匹配請求也可以翻轉 URLS。匹配方法將會返回 endpoint 和一個 URL 值字典。這個follow_short_link 路由實例有一個變量 short_id 。當我們在瀏覽器輸入 http://localhost:5000/foo我們將會得到如下的值: ~~~ endpoint = 'follow_short_link' values = {'short_id': u'foo'} ~~~ 我們沒有匹配到任何東西,他將會拋出一個 [NotFound](# "werkzeug.exceptions.NotFound") 異常,實質是一個 [HTTPException](# "werkzeug.exceptions.HTTPException") 異常。所有的 HTTP 異常將會跳轉 WSGI 應用渲染的默認錯誤頁面。所以我們只需要捕獲并返回他們。 如果一切順利,我們用 request 作為參數,所有的 URL 參數做作為關鍵字參數調用 on_+ endpoint 函數可以返回響應對象。 ### Step 5: 第一個視圖 讓我們開始第一個視圖: new URLs 視圖: ~~~ def on_new_url(self, request): error = None url = '' if request.method == 'POST': url = request.form['url'] if not is_valid_url(url): error = 'Please enter a valid URL' else: short_id = self.insert_url(url) return redirect('/%s+' % short_id) return self.render_template('new_url.html', error=error, url=url) ~~~ 思想不難理解。首先我們檢查請求方法是不是 POST,然后驗證得到的 URL 并插入到數據庫中,然后跳轉到一個詳細頁面。要實現這個,意味著我們需要在寫一個函數和一個輔助方法下面是 URL 驗證函數: ~~~ def is_valid_url(url): parts = urlparse.urlparse(url) return parts.scheme in ('http', 'https') ~~~ 為了向數據庫插入 URL,我們只需要在類中添加以下方法: ~~~ def insert_url(self, url): short_id = self.redis.get('reverse-url:' + url) if short_id is not None: return short_id url_num = self.redis.incr('last-url-id') short_id = base36_encode(url_num) self.redis.set('url-target:' + short_id, url) self.redis.set('reverse-url:' + url, short_id) return short_id ~~~ reverse-url: + URL 將會存放儲存ID。如果 URL 已經被提交過那么只需要返回存儲ID值,否則我們增加 last-url-id 鍵值并轉化為 base36,接下來我們將存儲連接和轉換連接存儲到 redis。下面就是轉化為 base 36 的函數: ~~~ def base36_encode(number): assert number >= 0, 'positive integer required' if number == 0: return '0' base36 = [] while number != 0: number, i = divmod(number, 36) base36.append('0123456789abcdefghijklmnopqrstuvwxyz'[i]) return ''.join(reversed(base36)) ~~~ 然而我們還沒有視圖的模板,不急,我們過一會就來寫模板。不過在這之前,我們先來完成另一個視圖。 ### Step 6: 重定向視圖 重定向視圖很簡單,它只需要從 redis 找到連接并重定向跳轉到它。另外我們還想添加一個計數器以便于統計連接被點擊頻率: ~~~ def on_follow_short_link(self, request, short_id): link_target = self.redis.get('url-target:' + short_id) if link_target is None: raise NotFound() self.redis.incr('click-count:' + short_id) return redirect(link_ta rget) ~~~ 在這種情況下,如果 URL 不存在,我們將會拋出一個 [NotFound](# "werkzeug.exceptions.NotFound")異常,通過 dispatch_request 函數返回一個 404 響應 ### Step 7: 描述視圖 鏈接描述視圖也是非常相似的,我們僅僅需要再渲染一個模板。除了目標 URL,我們還需要從 redis 查詢被點擊次數,如果在 redis 中沒有記錄,我們把它設為 0: ~~~ def on_short_link_details(self, request, short_id): link_target = self.redis.get('url-target:' + short_id) if link_target is None: raise NotFound() click_count = int(self.redis.get('click-count:' + short_id) or 0) return self.render_template('short_link_details.html', link_target=link_target, short_id=short_id, click_count=click_count ) ~~~ 要知道 redis 存的是字符串,所以你需要手動點擊次數轉化為 :int 。 ### Step 8: 模板 這里就是全部的模板,僅僅把它們放到 templates 文件夾就可以了。jinja2支持模板繼承,所以我們首先要創建一個 layout 模板,并用 blocks 占位。接下來設置jinja2以便于自動用html規則轉化字符串,我們不必自己花時間來做這些。同時它可以也防止 XSS 攻擊和渲染錯誤頁面。 *layout.html*: ~~~ <!doctype html> <title>{% block title %}{% endblock %} | shortly</title> <link rel=stylesheet href=/static/style.css type=text/css> <div class=box> <h1><a href=/>shortly</a></h1> <p class=tagline>Shortly is a URL shortener written with Werkzeug {% block body %}{% endblock %} </div> ~~~ *new_url.html*: ~~~ {% extends "layout.html" %} {% block title %}Create New Short URL{% endblock %} {% block body %} <h2>Submit URL</h2> <form action="" method=post> {% if error %} <p class=error><strong>Error:</strong> {{ error }} {% endif %} <p>URL: <input type=text name=url value="{{ url }}" class=urlinput> <input type=submit value="Shorten"> </form> {% endblock %} ~~~ *short_link_details.html*: ~~~ {% extends "layout.html" %} {% block title %}Details about /{{ short_id }}{% endblock %} {% block body %} <h2><a href="/{{ short_id }}">/{{ short_id }}</a></h2> <dl> <dt>Full link <dd class=link><div>{{ link_target }}</div> <dt>Click count: <dd>{{ click_count }} </dl> {% endblock %} ~~~ ### Step 9: 樣式 添加樣式可以使頁面比丑陋的黑色和白色看起來好一些。下面是一個簡單的樣式表: ~~~ body { background: #E8EFF0; margin: 0; padding: 0; } body, input { font-family: 'Helvetica Neue', Arial, sans-serif; font-weight: 300; font-size: 18px; } .box { width: 500px; margin: 60px auto; padding: 20px; background: white; box-shadow: 0 1px 4px #BED1D4; border-radius: 2px; } a { color: #11557C; } h1, h2 { margin: 0; color: #11557C; } h1 a { text-decoration: none; } h2 { font-weight: normal; font-size: 24px; } .tagline { color: #888; font-style: italic; margin: 0 0 20px 0; } .link div { overflow: auto; font-size: 0.8em; white-space: pre; padding: 4px 10px; margin: 5px 0; background: #E5EAF1; } dt { font-weight: normal; } .error { background: #E8EFF0; padding: 3px 8px; color: #11557C; font-size: 0.9em; border-radius: 2px; } .urlinput { width: 300px; } ~~~ ### Bonus: 改進 查看 Werkzeug 倉庫的 example 目錄可以找到這篇教程代碼,那里的版本可能有一些改進,比如一個定制的 404 頁面。 - [shortly in the example folder](https://github.com/mitsuhiko/werkzeug/blob/master/examples/shortly)
                  <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>

                              哎呀哎呀视频在线观看