從零開始用 Flask 搭建一個網站(一)

weixin_34290000發表於2016-08-15

前言

筆者之前未接觸過 Python,只是略懂一點前端,所以說從零開始也相差無幾吧。Flask 是一個輕量級的基於 Python 的框架,但是擴充套件性非常良好(Github 上 22000 多個 star 就知道群眾的選擇不無道理),其他的這裡就不多提了,下面就開始我們的網站搭建之路。

開始

環境搭建

首先需要準備 Python 開發環境,這裡推薦使用 pyenv 來安裝和管理 Python。筆者使用的是 Mac OSX(自帶 Python 2.6),直接使用如下命令安裝 pyenv:

brew install pyenv

之後要升級 pyenv 的話就用:

brew upgrade pyenv

安裝完以後,需要配置環境變數,如果使用 zsh,需要在 ~/.zshrc 加入以下程式碼:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
export PATH=$PATH:/sbin/
eval "$(pyenv init -)"

如果使用 bash,在 ~/.bash_profile 中加入即可。儲存後重啟終端即可。
如果要安裝 Python 3.5.2,可以用

pyenv install 3.5.2

檢視安裝的 Python 版本:

pyenv versions

切換區域性 Python 環境(這裡一般指在 Application 資料夾下切換環境)

pyenv local 3.5.2

關於其他更多命令,可以參考 Command.md

使用 IDE

這裡筆者推薦使用 PyCharm 來進行 python 專案開發。下載安裝後(這裡筆者下載的是 Professional 版本),新建一個 Flask 專案,然後指定目錄、python 環境:

1745101-a6a3592b958fad2f.png

完成後點選 Create,這樣就建立了一個 Flask 專案,如果沒有安裝 Flask,PyCharm 會自動下載安裝。如果想使用 virtualenv,可以參考下一個步驟。

使用虛擬環境

使用虛擬環境可以方便地安裝 Flask 而且可以在系統的 Python 直譯器中避免包的混亂和版本的衝突。Python 3.3以後原生支援虛擬環境,命令為 pyvenv。可以使用如下命令建立虛擬環境(進入剛才建立的 Flask 專案資料夾):

pyvenv venv

如果使用 Python 2.7或者以下版本,可以使用第三方工具 virtualenv 建立虛擬環境:

sudo easy_install virtualenv

以上命令就可以安裝 virtualenv(如果沒有安裝 easy_install,需要手動安裝,而 pyvenv 已經自帶 pip 和 easy_install)。下一步使用 virtualenv 命令在資料夾中建立 Python 虛擬環境:

virtualenv venv

完成後,會在 Flask 專案下生成 venv 資料夾。在使用虛擬環境之前,要先使用(pyvenv 和 virtualenv 建立的虛擬環境是一樣的,因此以下命令均可使用):

source venv/bin/activate

來啟用,如果要退出虛擬環境,可以使用:

deactivate

建立的虛擬環境會自動安裝 pip 和 easy_install,接下來可以使用:

pip install flask

接下來就可以在 Flask 中開始自由地遨(入)遊(坑)啦!

Flask 程式結構

在介紹 Flask 的程式結構之前,先來看看標準 Flask 專案的專案結構(筆者以為從巨集觀到微觀的方式可以更快的瞭解一個東西)。使用 PyCharm 新建 Flask 專案後,專案結構如下圖所示:

1745101-9453a5cd5f9321ce.png

只有三個資料夾(venv 資料夾已經用命令列生成了)和一個簡單的入口類,接下來要把專案結構改造成標準的 Flask 專案結構:

1745101-a5b81ade0bef47c9.png

Flask 專案有4個頂級資料夾:

  • app ——(本例中是 jbox)Flask 程式儲存在此資料夾中
  • migrations ——包含資料庫遷移指令碼(安裝了 flask-migrate 後自動生成)
  • tests ——單元測試放在此資料夾下
  • venv ——Python 虛擬環境

同時還有一些檔案:

  • requirements.txt —— 列出了所有的依賴包,以便於在其他電腦中重新生成相同的環境
  • config.py 儲存配置
  • manage.py 啟動程式或者其他任務
  • gun.conf Gunicorn 配置檔案

雖然新建的 Flask Project 已經可以執行,但是我們還是要按照標準的 Flask 程式來改造專案結構。下面我們就來改造一下 TestProject。
在命令列中依次使用以下命令來安裝 Flask 擴充套件:

pip install flask-script
pip install flask-sqlalchemy
pip install flask-migrate

flask-script 可以自定義命令列命令,用來啟動程式或其它任務;flask-sqlalchemy 用來管理資料庫的工具,支援多種資料庫後臺;flask-migrate 是資料庫遷移工具,該工具命令整合到 flask-script 中,方便在命令列中進行操作。

然後建立 config.py 檔案,內容如下:

config.py

import os

basedir = os.path.abspath(os.path.dirname(__file__))

class config:    
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'this is a secret string' 
    SQLALCHEMY_TRACK_MODIFICATIONS = True  

     @staticmethod    
     def init_app(app):        
        pass

class DevelopmentConfig(config):    
    DEBUG = True    
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \        
    'sqlite:///' + os.path.join(basedir, 'dev')

class TestingConfig(config):    
    TESTING = True    
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \                              
    'sqlite:///' + os.path.join(basedir, 'test')

class ProductionConfig(config):    
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \                              
    'sqlite:///' + os.path.join(basedir, 'data.sqlite')

config = {    
    'development': DevelopmentConfig,    
    'testing': TestingConfig,    
    'production': ProductionConfig,    
    'default': DevelopmentConfig
}

config 顧名思義,儲存了一些配置變數。SQLALCHEMY_DATABASE_URI 變數在不同的配置中被賦予了不同的值,這樣就可以在不同的環境中切換資料庫。如果是遠端資料庫則從環境變數中讀取 URL,否則在本地路徑中建立。

接下來建立一個 app 資料夾,並在此資料夾中建立一個 __init__.py 檔案(init 前後都有兩個下劃線):

app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config

db = SQLAlchemy()

def create_app(config_name):    
    app = Flask(__name__)    
    app.config.from_object(config[config_name])    
    config[config_name].init_app(app)
    db.init_app(app)    
    
    //此處預設了部分程式碼,後面會加上
    return app

create_app() 就是程式的工廠函式,引數就是配置類的名字,即 config.py,其中儲存的配置可以使用 from_object() 方法匯入。

接下來要解釋兩個重要的概念——路由和檢視函式。客戶端把請求發給 Web 伺服器,Web 伺服器再把請求發給 Flask 程式例項,Flask 程式例項需要知道每個 URL 請求要執行哪些程式碼,所以儲存了一個 URL 到 Python 函式的對映關係。處理 URL 和函式之間關係的程式稱為路由,這個函式稱為檢視函式。例如:

@app.route('/')
def index():
    return '<h1>Hello World</h1>'

這裡使用 app.route 修飾器來定義路由,app 指 Flask 程式例項物件,後面可以看到使用藍本管理路由後,由藍本例項物件來取代 app。Flask 使用藍本來定義路由,在藍本中定義的路由處於休眠狀態,直到藍本註冊到程式上後,路由真正成為程式的一部分。藍本通常使用結構化的方式儲存在包的多個模組中。接下來在 app 資料夾下建立一個子資料夾 main,並在 main 中建立 __init__.py(如果使用 PyCharm,這裡有個快捷方式,右鍵點選 app 資料夾,在選單中選擇 new -> Python Package,在彈出的對話方塊中填寫包名然後確認即可):

app/main/__ init__.py

from flask import Blueprint
//例項化 Blueprint 類,兩個引數分別為藍本的名字和藍本所在包或模組,第二個通常填 __name__ 即可
main = Blueprint('main', __name__)

from . import views, errors

最後引用了兩個檔案,之所以寫在最後是因為避免迴圈匯入依賴,因為接下來在 main 資料夾下 建立的 views.py 和 errors.py 都要匯入藍本 main。

app/main/views.py

from flask import render_template
//匯入藍本 main
from . import main

@main.route('/')
def index():    
    return render_template('index.html')

在之前路由的概念解釋中,index 函式直接返回了 HTML 字串(通常不這麼做),這裡則使用了 render_templete() 函式來渲染 index.html,並返回。Flask 使用了 Jinja2 引擎來渲染模板,模板檔案都放在 templates 資料夾下,並且只能命名為 templates,否則 Jinja2 會丟擲 TemplageNotFound 異常。由於我們的app 是一個 Python Package(在目錄中包含 __init__.py 預設成為 Python Package),所以需要將 templates 放在 app 目錄下。在 app 下 中建立名為 templates 的資料夾,在 PyCharm 中右鍵點選該資料夾,然後選擇 Make Directory As -> Template Folder,如圖:

1745101-b70233c619c2fa15.png

接下來在 templates 下新建一個 index.html 和 404.html 模板:

app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>    
    <meta charset="UTF-8">    
    <title>index</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>

app/templates/404.html

<!DOCTYPE html>
<html lang="en">
<head>    
    <meta charset="UTF-8">    
    <title>Not Found</title>
</head>
<body>
<h1>Can't find request page!</h1>
</body>
</html>

之後會講解模板的具體用法,現在接著來定義 errors.py:

app/main/errors.py

from flask import render_template
from . import main

@main.app_errorhandler(404)
def page_not_found(e):    
    return render_template('404.html'), 404

上面的步驟是讓程式的路由儲存在 views.py 中,而錯誤處理交給 errors.py,這兩個模組已經和藍本 main 關聯起來了(在藍本中匯入了這兩個模組),現在需要在工廠函式中註冊藍本 main。將如下程式碼加入到上面預設程式碼中即可:

app/__init__.py

def create_app(config_name):
    #...
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    return app

最後兩個步驟是建立 requirements.txt 以及啟動指令碼 manage.py。程式中必須包含一個 requirements.txt 檔案,用於記錄所有的依賴包和版本號,便於在其它電腦上建立相同的開發環境。直接在終端使用如下命令即可建立 requirements.txt 檔案:

pip freeze > requirements.txt

以後安裝了新的依賴包或者升級版本後,重新執行該命令即可更新 requirements.txt 檔案。如果要手動新增也可以,在 PyCharm 中用 Command + , 喚出 Preferences 對話方塊,然後選擇 Project -> Project Interpreter 即可檢視所有的依賴包及其版本號(還有最新版本號提示),如圖:

1745101-2519f815e5934d45.png

如果要在另一臺電腦上建立這個虛擬環境的完全副本,執行以下命令即可:

pip install -r requirements.txt

最後建立啟動指令碼 manage.py:

manage.py

import os
from app import create_app, db
from flask_script import Manager, Shell
from flask_migrate import Migrate, MigrateCommand

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)

def make_shell_context():    
    return dict(app=app, db=db)

manager.add_command("shell",Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)

if __name__ == '__main__':    
    manager.run()

這個指令碼首先建立程式,然後增加了兩個命令:shell 和 db,我們之後可以在命令列中直接使用。

到此為止,我們的目錄結構如下:

1745101-d70859146f1cb5ef.png

執行

現在就來啟動我們的程式,在命令列中進入 TestProject 目錄,然後執行如下命令即可執行:

python manage.py runserver

命令列執行截圖如下:

1745101-2edf40b2ec3b12b9.png

Flask 預設的本機地址為:http://127.0.0.1:5000/ ,現在用瀏覽器開啟這個地址,應該可以看到如下頁面:

1745101-917907dd42367531.png

到這一步,我們的第一個 Flask 程式已經完成了!雖然還沒有建立資料庫,頁面也非常糟糕,但是之後我們會一步步進行完善!
本文參考書籍 Flask Web 開發:基於 Python 的 Web 應用開發實戰(作者: Miguel Grinberg)

相關文章