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