Flask_0x05 大型程序結構

0x1 項目結構html

        git checkout 7apython

    多文件Flask程序基本結構git

    多文件 Flask 程序的基本結構sql

|-flasky |-app/
      |-templates/
      |-static/
      |-main/
          |-__init__.py           |-errors.py           |-forms.py           |-views.py       |-__init__.py       |-email.py       |-models.py   |-migrations/
  |-tests/
      |-__init__.py       |-test*.py   |-venv/
|-requirements.txt |-config.py |-manage.py

    Flask程序通常保存在app包中shell

    migrations包含數據庫遷移腳本數據庫

    單元測試在tests包中flask

    venv包含Python虛擬環境bootstrap

    requirements.txt列出全部依賴包session

    config.py 存儲配置app

    manage.py 用於啓動程序以及其餘程序任務

 

0x2 配置選項

    config.py:程序的配置

import os basedir = os.path.abspath(os.path.dirname(__file__)) class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' SQLALCHEMY_COMMIT_ON_TEARDOWN = True MAIL_SERVER = 'smtp.googlemail.com' MAIL_PORT = 587 MAIL_USE_TLS = True MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]' FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>' FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN') @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, 'data-dev.sqlite') class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-test.sqlite') 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包含通用配置,子類定義專用配置

 

0x3 程序包
  3.1 app
   程序包保存全部代碼、模板、靜態文件,這個包一般稱爲app

    數據庫模型和電子郵件支持函數保存爲app/models.py和app/email.py

  3.2 工廠函數

    把建立程序實例移到可顯式調用的工廠函數中,這樣能夠建立多個程序實例

    app/__init__.py

from flask import Flask from flask_bootstrap import Bootstrap from flask_mail import Mail from flask_moment import Moment from flask_sqlalchemy import SQLAlchemy from config import config bootstrap = Bootstrap() mail = Mail() moment = Moment() db = SQLAlchemy() def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) bootstrap.init_app(app) mail.init_app(app) moment.init_app(app) db.init_app(app) from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app

    create_app()就是程序的工廠函數,接受一個參數,是程序使用的配置名

    配置類在config.py中定義,其中保存的配置可使用Flask app.config配置對象提供的from_object()方法直接導入程序

    配置對象則能夠經過名字從config字典中選擇

    在以前建立的擴展對象上調用init_app()能夠完成初始化過程

  3.3 在藍本中實現程序功能

    藍本能夠定義路由,在藍本中定義路由處於休眠狀態,避免app.route定義路由不及時等問題

    app/main/__init__.py:建立藍本

from flask import Blueprint main = Blueprint('main', __name__) from . import views, errors

    經過實例化一個Blueprint類對象能夠建立藍本,這個構造函數的兩個必須指定的參數:

    藍本的名字和藍本所在的包或模塊,大多數狀況第二個參數使用__name__變量

    程序的路由在 app/main/views.py模塊中,錯誤處理程序在app/main/errors.py模塊中

    導入這兩個模塊就能把路由和錯誤處理程序與藍本關聯起來(在app/main/__init__.py末尾導入)

 

    app/__init__.py:註冊藍本

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

    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 @main.app_errorhandler(500) def internal_server_error(e): return render_template('500.html'), 500

    要想註冊程序全局的錯誤處理程序,必須使用app_errorhandler

    app/main/views.py:藍本中定義的程序路由

from flask import render_template, session, redirect, url_for, current_app from .. import db from ..models import User from ..email import send_email from . import main from .forms import NameForm @main.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.name.data).first() if user is None: user = User(username=form.name.data) db.session.add(user) session['known'] = False if current_app.config['FLASKY_ADMIN']: send_email(current_app.config['FLASKY_ADMIN'], 'New User', 'mail/new_user', user=user) else: session['known'] = True session['name'] = form.name.data return redirect(url_for('.index')) return render_template('index.html', form=form, name=session.get('name'), known=session.get('known', False))

    在藍本中url_for()用法不一樣,Flask爲藍本的所有端點加一個命名空間,命名空間就是藍本的名字

    因此視圖函數index()註冊的端點名是main.index,其URL使用url_for('main.index')獲取

    url_for()支持簡寫的端點形式,在藍本中能夠省略藍本名,但跨藍本的重定向的端點名必須帶有命名空間

    表單對象也要移到藍本中,保存於 app/main/forms.py模塊

 

0x4 啓動腳本

    頂級文件夾中的manage.py文件用於啓動腳本

    manage.py:啓動腳本

#!/usr/bin/env python
import os from app import create_app, db from app.models import User, Role 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, User=User, Role=Role) manager.add_command("shell", Shell(make_context=make_shell_context)) manager.add_command('db', MigrateCommand) if __name__ == '__main__': manager.run()

    若是已經定義了環境變量FLASK_CONFIG,則從中讀取配置名,不然使用默認配置

    而後初始化Flask-Script、Flask-Migrate和爲Python shell定義的上下文

    腳本中加入shebang聲明,能夠經過./manage.py執行腳本

 

0x5 需求文件

    程序中包含requirements.txt,用於記錄全部依賴包及版本號

    pip自動生成requirements.txt文件

(venv) $ pip freeze >requirements.txt

    若是要建立這個虛擬環境的副本

(venv) $ pip install -r requirements.txt

 

0x6 單元測試

    這個測試使用Python標準庫中的unittest包編寫

    瞭解更多unittest包編寫測試:https://docs.python.org/2/library/unittest.html

import unittest from flask import current_app from app import create_app, db class BasicsTestCase(unittest.TestCase): def setUp(self): self.app = create_app('testing') self.app_context = self.app.app_context() self.app_context.push() db.create_all() def tearDown(self): db.session.remove() db.drop_all() self.app_context.pop() def test_app_exists(self): self.assertFalse(current_app is None) def test_app_is_testing(self): self.assertTrue(current_app.config['TESTING'])

    setUp()方法建立一個測試環境,相似於運行中的程序

    首先,使用測試配置建立程序,而後激活上下文,這樣可確保能在測試中使用current_app

    而後建立一個全新的數據庫,以備不時之需,數據庫和程序上下文在tearDown()方法中刪除

    第一個測試確保程序實例存在,第二個測試確保程序在測試配置中運行

    若想把tests文件夾做爲包使用,須要添加tests/__init__.py

    manage.py:啓動單元測試命令

@manager.command def test(): """Run the unit tests."""
    import unittest tests = unittest.TestLoader().discover('tests') unittest.TextTestRunner(verbosity=2).run(tests)

    單元測試運行:

(venv) $ python manage.py test test_app_exists (test_basics.BasicsTestCase) ... ok test_app_is_testing (test_basics.BasicsTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.187s OK

0x7 建立數據庫

    若是使用Flask-Migrate跟蹤遷移,可以使用以下命令建立數據表或升級到最新修訂版:

(venv) $ python manage.py db upgrade
相關文章
相關標籤/搜索