日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Flask Web 開發學習稿(三)

Flask Web 開發學習稿(三)

來源:程序員人生   發布時間:2016-06-20 07:47:58 閱讀次數:2888次

第6章 電子郵件

當我們需要在特定事件產生時提示用戶,包裝了 smtplibFlask-Mail 擴大能更好的和 Flask 集成
安裝 pip install flask-mail
Flask-Mail 連接到 SMTP 服務器,如果不進行配置,Flask-Mail 會連接 localhost 上的端口 25

配置 默許值 說明
MAIL_SERVER localhost Email服務器的ip地址或主機名
MAIL_PORT 25 Email服務器端口
MAIL_USE_TLS False 啟用傳輸層安全協議
MAIL_USE_SSL False 啟用安全套接曾協議
MAIL_USERNAME None Email用戶名
MAIL_PASSWORD None Email密碼

使用外部 SMTP 服務器更加方便

from flask.ext.mail import Mail app.config['MAIL_SERVER'] = 'mail.xxx.com' app.config['MAIL_PORT'] = '587' app.config['MAIL_USE_TLS'] = 'True' app.config['MAIL_USERNAME'] = 'username' app.config['MAIL_PASSWORD'] = 'pwd' mail = Mail(app)

將賬戶和密碼寫在程序里太不安全了,為了保護敏感信息,需要讓腳本從環境變量中導入這些信息

app.config['MAIL_USERNAME'] = os.environ.get('MALI_USERNAME') app.config['MAIL_PASSWORD'] = os.environ.get('MALI_PASSWORD')

如何設置環境變量呢?

# Linux 或 Mac OS X export MALI_USERNAME=<YOU_USERNAME> export MALI_PASSWORD=<YOU_PASSWORD> # Windows set MALI_USERNAME=<YOU_USERNAME> set MALI_PASSWORD=<YOU_PASSWORD>

在程序中集成發送電子郵件功能

from flask.ext.mail import Message app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]' app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>' def send_email(to, subject, template, **kwargs): msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject, sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to]) msg.body = render_template(template + '.txt', **kwargs) msg.html = render_template(template + '.html', **kwargs) mail.send(msg)

這兩個程序特定配置項,分別定義了郵件主題的前綴和發件人的地址
send_email() 函數的參數分別為收件人地址,主題,渲染郵件正文的模版和關鍵字參數列表
指定模版時不能包括擴大名,這樣才能使用兩個模版分別渲染純文本正文和富文本正文
調用者將關鍵字參數傳給 render_template() 函數以便在模版中使用,進而生成電子郵件正文,下面修改視圖函數

app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN') #... @app.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 app.config['FLASKY_ADMIN']: send_email(app.config['FLASKY_ADMIN'], 'New User', 'mail/new_user', user=user) else: session['known'] = True session['name'] = form.name.data form.name.data = '' return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'), known=session.get('known', False))

我們要創建兩個模版文件,分別用于渲染純文本和 HTML 版的郵件正文,這兩個模版文件都保存在 tmplates 文件夾下的 mail 子文件夾中,以便和普通模版辨別開來。電子郵件的模版中要有1個模版參數是用戶,因此調用 send_mail() 函數時要以關鍵字參數的情勢傳入用戶
這樣的程序會在發送郵件的時候造成短暫阻塞,異步發送電子郵件來消除這類沒必要要的延遲

from threading import Thread def send_async_email(app, msg): with app.app_context(): mail.send(msg) def send_email(to, subject, template, **kwargs): msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject, sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to]) msg.body = render_template(template + '.txt', **kwargs) msg.html = render_template(template + '.html', **kwargs) thr = Thread(target=send_async_email, args=[app, msg]) thr.start() return thr

很多 Flask 擴大都假定已存在激活的程序上下文和要求上下文,Flask-Mail 中的 send() 函數使用 current_app,因此必須激活程序上下文,不過不同線程中履行mail.send()函數時,程序上下文要使用 app.app_context() 人工創建
當你需要大量發送電子郵件時,使用 Celery 任務隊列更適合

第7章 大型程序的結構

現在我們已完成了很多功能的學習,但是隨著程序愈來愈大,我們將學會如何組織大型程序的結構

7.1 項目結構

├─Flsky │ │─app # Flask 程序| ├─static| |─templates| |─main| | │-__init__.py │ │ | |-errors.py │ │ | |-forms.py │ │ | |-views.py │ │ |-__init__.py │ │ |-email.py │ │ |-models.py | |-migrations # 數據庫遷移腳本 | |-tests # 單元測試 | | |-__init__.py | | |-test*.py|-config.py # 貯存配置|-manage.py # 用于啟動程序和其他的程序任務|-requirements.txt # 列出全部依賴包 | └─ venv # python虛擬環境

7.2 配置選項

從現在開始我們我們的配置不會再像之前那樣用簡單的字典結構,而是使用配置類

#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 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 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') 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 }

配置類可以定義init_app()方法,其參數是程序實例,在這個方法中,可以履行對當前環境的配置初始化,現在基類 Config 中的init_app()方法為空

7.3 程序包

程序包用來保存程序的所有代碼、模版和靜態文件。

7.3.1 使用程序工廠函數

把創建進程移到可顯式調用的工廠函數中,程序的工廠函數在 app 包的構造文件中定義
構造文件導入了太多正在使用的 Flask 擴大,由于還沒有初始化所需的程序實例,所以沒有初始化擴大,創建擴大類時沒有向構造函數傳入參數
create_app() 函數就是程序的工廠函數,接受1個參數,是程序使用的配置名
配置類在 config.py 文件中定義,其中保存的配置可使用 Flask app.config 配置對象提供的 from_object() 方法直接導入程序。至于擴大對象,則可以通過名字從 config 字典當選擇。
程序創建配置好后,就可以初始化擴大了,在之前創建的擴大對象上調用 init_app() 可以完成初始化進程

# app/__init__.py from flask import Flask, render_template from flask.ext.bootstrap import Bootstrap from flask.ext.mail import Mail from flask.ext.moment import Moment from flask.ext.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) # 附加路由和自定義毛病頁面 return app

7.3.2 在藍本中實現程序的功能

在單腳本程序中,程序實例存在于全局作用域中,路由可以直接使用 app.route 修飾器定義。但是現在利用程序實例是運行時創建的,app.route 只在在 create_app() 以后才存在,這時候定義路由就太晚了
在藍本中注冊的路由都處于休眠狀態,直到藍本注冊到程序上后,路由才真正成為程序的1部份。使用位于全局作用域的藍本時,定義路由的方法幾近和單腳本程序1樣
為了取得最大的靈活性,程序包中創建了1個子包用于保存藍本

app/main/__init__.py from flask import Blueprint main = Blueprint('main', __name__) from . import views, errors

通過實例化1個藍本類對象可以創建藍本,構造函數有兩個參數:藍本的名字和藍本所在的模塊或包,大多數情況下,Python的 __name__變量就是第2個參數所需要的值
利用程序的路由放在app/main/views.py模塊中, 毛病處理放在app/main/errors.py中。導入這些模塊以后,路由和毛病處理就和藍本關聯起來了。
有1點要注意,路由和毛病處理模塊要在 app/__init__.py 的底部被導入,由于views.py 和 errors.py 要導入 main blueprint,所以為了不循環依賴我們要等到 main 被創建出來才能夠導入路由和毛病處理。
藍本在工廠函數 create_app() 中注冊到程序上

# app/__init__.py 注冊藍本 def create_app(config_name): # ... from main import main as main_blueprint app.register_blueprint(main_blueprint) return app

毛病處理程序以下

#app/main/error.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

如果使用 errorhandler 修飾器,只有藍本中的毛病才能觸發處理程序,要想注冊程序全局的毛病處理程序,必須使用 app_errorhandler
在藍本中定義路由以下

# app/main/views.py from datetime import datetime from flask import render_template, session, redirect, url_for from . import main from .forms import NameForm from .. import db from ..models import User @main.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): # ... return redirect(url_for('.index')) return render_template('index.html', form=form, name=session.get('name'), known=session.get('known', False), current_time=datetime.utcnow())

在藍本中的視圖函數的區分

  1. 路由修飾器由藍本提供
  2. url_for() 的用法不同

Flask 會為藍本中的全部端點都加上1個命名空間,這樣就能夠在不同的藍本中使用相同的端點名定義視圖函數,而不會產生沖突。命名空間就是藍本的名字(藍本構造函數的第1個參數),所以視圖函數 index() 注冊的端點名是 main.inedx 其 URL 使用 url_for('main.index') 獲得
為了完全修改程序的頁面,表單對象也要移到藍本中,保存于 app/main/forms.py 模塊

7.4 啟動腳本

manage.py 文件用于啟動程序

#!/usr/bin/env python import os from app import create_app, db from app.models import User, Role from flask.ext.script import Manager, Shell from flask.ext.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 定義的上下文

7.5 需求文件

pip 可使用以下命令自動生成這個文件
pip freeze >requirements.txt
當你在另外一個環境中準備安裝這些依賴時,履行以下命令
pip install -r requirements.txt

7.6 單元測試

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()tearDown() 方法在每一個測試方法履行前后都會運行,任何以test_ 開頭的方法都會被當作測試方法來履行。setUp()方法創建了測試所需的環境, 他首先創建了利用程序實例用作測試的山下文環境,這樣就可以確保測試拿到current_app, 然后新建了1個全新的數據庫數據庫和利用程序實例最后都會在tearDown() 方法被燒毀。

第1個測試確保了利用程序實例是存在的,第2個測試利用程序實例在測試配置下運行。為了確保測試文件夾有正確的包結構,我們需要添加1個tests/__init__.py 文件,這樣單元測試包就可以掃描所有在測試文件夾中的模塊了。

為了運行單元測試,我們可以在manage.py中添加1個自定義命令,

@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.001s OK

7.7 創建數據庫

首選從環境變量中讀取數據庫的 URL,同時還提供了1個默許的 SQLite 數據庫做備用
可使用以下命令創建數據表或升級到最新修訂版本
python mange.py db upgrade

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产精品久久久久久久久久久不卡 | 精品伦精品一区二区三区视频 | 久久国产精品99久久久久久牛牛 | 这里只有精品久久 | 日本视频网址 | 欧美日韩亚洲天堂 | 色一情一乱一伦一区二区三区 | 九九热久久久99国产盗摄蜜臀 | 丁香六月色婷婷 | 国产不卡免费视频 | 91伦理视频在线观看 | 欧美日韩高清 | 三级在线免费 | 国产视频二区三区 | 国产毛片久久 | 欧美日韩一区三区 | 网站黄色一级片 | 国产精品一区一区 | 精品一区二区三区蜜桃 | 日韩av成人在线观看 | 日韩中文一区 | 综合久久婷婷 | 国产精品一区一区三区 | 久久最新 | a黄色片 | 国产骚片 | 久久精品视频一区二区 | 亚洲欧洲自拍偷拍 | 国产一区二区三区免费视频 | 韩国一级片在线播放 | 国产精品视频一区二区三区 | 欧美日韩成人 | а√在线中文网新版地址在线 | 国产精品热久久久久夜色精品三区 | 国产日韩一区二区 | 欧美日韩免费看 | 91欧美精品成人综合在线观看 | 免费视频二区 | 2019国产精品视频 | 天堂成人国产精品一区 | 麻豆乱码国产一区二区三区 |