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 命令来初始化DB @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')