1 Project Layout
規劃project layout
1 Project目錄: 作爲project的根目錄,組織application
2 Project下的子目錄:
2.1 <application> 包含code和文件的python package,其下有init.py
2.2 <tests> 包含tests模塊的目錄
2.3 <venv> 安裝flask和其他依賴的virtual environment
3 setup.py 指導如何安裝project
2 Application Setup
概念
application factory: 在一個函數中完成Flask實例的創建,配置。
configuration and URLs, will be registered with this class Flask
init.py有兩個duty: 一個是指明application目錄是一個Python package,另外一個就是創建Application factory 函數。
案例
def create_app(test_config=None):
#create and configure the app
#name指明app的path,用來setup 其它路徑
#instance_relative_config指明app的configuration文件對應到instance目錄
app = Flask(name,instance_relative_config=True)
#設置app默認的配置
app.config.from_mapping(
#加密數據
SECRET_KEY='dev',
#指明數據庫的path
DATABASE=os.path.join(app.instance_path,'flaskr.sqlite'),
)
if test_config is None:
#從config.py中獲取配置,override默認的configuration
app.config.from_pyfile('config.py',silent=True)
else:
app.config.from_mapping(test_config)
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route('/')
def hello():
return 'Hello'
return app
運行
export FLASK_APP=flaskr #package name
export FLASK_ENV=development
flask run
note:
默認的application factory 的名字是create_app,如果修改需要指定FLASK_APP=flaskr:create_app
3 Define and Access the Database
3.1 Connect to the Database
#該connection與每一個request是bind的,其在處理request時被創建,在返回response前被關閉。
#g對每一個request來說,是唯一的。在請求中,用來存儲被多個函數訪問的對象。
#sqlite3.Row告訴創建的connection, 返回的數據像數據字典
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
3.2 Create the Tables
#使用
def init_db():
db = get_db()
#根據package路徑,打開一個file。這樣就不用考慮path問題了
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
#定義了a command line 叫init-db
#使用flask init-db 命令來初始化DBbr/>@click.command('init-db')
@with_appcontext
def init_db_command():
"""Clear the existing data and create new tables."""
init_db()
click.echo('Initialized the database.')
3.3 Register with the Application
init db和close db應該在Application instance中註冊
def init_app(app):
#在返回response時,告訴APP調用close_db來清理
app.teardown_appcontext(close_db)
#添加一個new command,可以通過flask 來調用
app.cli.add_command(init_db_command)
#在factor中調用以下code
from . import db
db.init_app(app)
4 Blueprints and Views
概念:
Blueprint:一種組織view和code的組方式,而不是直接在Application張註冊view和code 。
view and code 在Blueprint中 register,Blueprint在Application中註冊。
4.1 Create a Blueprint
#創建一個名爲auth,使用name來指定創建位置,
url_prefix說明所有與blueprint相關的URL前綴爲/auth
bp = Blueprint('auth', name, url_prefix='/auth')
在factory中import和register blueprint
from . import auth
app.register_blueprint(auth.bp)
4.2 The First View: Register
URL: /auth/register
#使用blueprint來指明URL路由,當請求/auth/retister時,call 視圖register
@bp.route('/register', methods=('GET', 'POST'))
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
if not username:
error = 'Username is required.'
elif not password:
error = 'Password is required.'
elif db.execute(
'SELECT id FROM user WHERE username = ?', (username,)
).fetchone() is not None:
error = 'User {} is already registered.'.format(username)
if error is None:
#函數generate_password_hash生成password的hash值
db.execute(
'INSERT INTO user (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
db.commit()
return redirect(url_for('auth.login'))
#存儲信息,可以被template來使用
flash(error)
return render_template('auth/register.html')