源地址:http://flask.pocoo.org/docs/1.0/tutorial/
1.1.项目布局
创建一个项目目录并进入:
mkdir flask-tutorial
cd flask-tutorial
然后跟着installation instructions建立一个python虚拟环境和安装Flask环境。
该教程假设你从现在开始都是在flask-tutorial
目录下进行操作的。在代码片段最上方的文件名称都是相对于该目录的。
一个Flask应用可以简单到只有一个文件:
hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
然而随着项目越做越大,将所有的代码放到一个文件中显然是不合理的。我们可以使用包将不同的模块分隔开来,如果哪需要用到这个模块,就进行模块的引入。当然,这教程也是这种做法。
该项目将包含以下几项:
-
flaskr/
,包含你应用代码与文件的python目录。 -
tests/
,包含测试模块的目录。 -
venv/
,安装Flask及其依赖包的python虚拟环境。 - 安装文件告诉Python如何安装你的项目。
- 版本控制文件,例如 git。你应该养成对你所有的项目进行版本控制的习惯。
- 将来你会添加的项目文件。
最后,你的项目布局看起应该是这样:
/home/user/Projects/flask-tutorial
├── flaskr/
│ ├── init.py
│ ├── db.py
│ ├── schema.sql
│ ├── auth.py
│ ├── blog.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── blog/
│ │ ├── create.html
│ │ ├── index.html
│ │ └── update.html
│ └── static/
│ └── style.css
├── tests/
│ ├── conftest.py
│ ├── data.sql
│ ├── test_factory.py
│ ├── test_db.py
│ ├── test_auth.py
│ └── test_blog.py
├── venv/
├── setup.py
└── MANIFEST.in
1.2.设置应用程序
一个Flask应用就是一个Flask
类的实例。所有有关应用的一切,例如配置和URLS,都要注册到这个类中。
创建Flask应用程序最直接的方法是直接在代码顶部创建一个全局的Flask实例。对于某些情况,这是一个行之有效的方式,但随着项目的增长,它可能会导致一些棘手的问题。
你可以在一个方法中创建Flask实例来代替创建全局的Flask实例。这个方法被称为工厂方法。所有的配置,注册和其他需要初始化都在一个方法中进行处理,然后返回初始化好的实例。
1.2.1.应用的工厂化方法
是时候进行编码啦!创建flaskr
目录并添加__init__.py
文件。__init__.py
承担两个职责:1.它包含了应用的工厂方法。2.告诉Python解析器,flaskr
目录当成一个Python包来处理。
mkdir flaskr
flaskr/__init__.py
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
@app.route('/hello')
def hello():
return 'Hello, World!'
return app
create_app
是这个应用的工厂方法。你将在教程的后面继续添加它的逻辑,但它已经做了很多事情。
1.app = Flask(__name__, instance_relative_config=True)
创建Flask
实例。
-
__name__
指的是当前Python模块的名称。该app需要知道它所在的位置从而设置一些路径,__name__
参数就很便利。 -
instance_relative_config=True
告诉app配置文件是相对于实例文件夹的。实例文件是位于flaskr
包的外部,它可以保存不被版本控制的本地数据,例如密钥配置和数据库语句。
2.app.config.from_mapping()设置一些app将会使用的默认配置:
-
SECRET_KEY被Flask和插件用于加密,保证数据的安全。在开发过程中,FLask给我们提供了一个便利的值
'dev'
,当发布时,该值应该被一个随机值覆写。 -
DATABASE
指定了存放SQLite数据库文件的路径。它是在app.instance_path路径下,app.instance_path
是Flask指定的实例目录。在下一章节会讲述更多的关于数据库的内容。
3.app.config.from_pyfile()会使用实例文件夹下的config.py
(如果存在)文件中的值覆盖默认配置。举个例子,当发布时,这个函数可以用来设置一个真实的SECRET_KEY
。
-
test_config
也可以传递给工厂,并且将会被用于替换实例配置。在这个教程后面点你将会写到的单元测试能够被单独配置——独立于任何配置的开发值。
4.os.makedirs()主要是确认app.instance_path是否存在。Flask不会自动地创建实例目录,但是实例文件确实需要创建,因为你要将你的SQLite数据库文件存储在实例目录下。
5.@app.route()创建一个简单的路由,这样你可以在进入教程其他部分之前看到一个可运行的应用。在这个例子中,应用创建了一个指向/hello
url的连接和一个返回字符串'Hello, World!'
响应的方法。
1.2.2.启动应用程序
现在你可以使用flask
命令来启动应用。在终端告诉Flask在哪能找到你的应用,并以开发环境的模式启动它。
无论何时一个页面抛出异常的时候,开发模式都会显示交互式的调式器。无论何时你修改了项目代码,开发模式都会重启服务。你可以让它保持运行,只需按照教程重新加载浏览器页面即可。
对于Linux和Mac系统:
export FLASK_APP=flaskr
export FLASK_ENV=development
flask run
对于Windows命令行,使用set
替代export
:
set FLASK_APP=flaskr
set FLASK_ENV=development
flask run
你将会看到控制台的输出大致如下:
* Serving Flask app "flaskr"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 855-212-761
在浏览器中访问http://127.0.0.1:5000/hello
,你应该能够看到 “Hello, World!” 信息。恭喜你,你正在运行你自己的Flask网络应用。
1.3.定义和访问数据库
该应用将会使用SQLite数据库来存储用户与请求数据。Python在sqlite3模块中内置了对SQLite的支持。
SQLite非常便利,因为它不需要额外的分离的数据库服务并且它是内置在Python中。然而,在同一时间,多个并发请求同时试图将数据写入数据库,请求响应时间将会延长,因为每次写入都是顺序发生的。小应用不会注重这些。一旦你的应用变大,你可能希望切换到其他数据库。
该教程不会详细介绍SQL语句。如果你不熟悉它,你可以在SQLite文档中找到该语言的描述。
1.3.1.连接数据库
当你想操作一个SQLite数据库,首先你要做的是创建一个SQLite连接。所有的查询与操作都是基于这个连接的。当完成任务后,记得关闭这个连接。
在一个网络应用中,一个连接通常对应一个请求。一般是在处理请求时的某个阶段创建连接,然后在发送响应之前关闭这个连接。
flaskr/db.py
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
g是一个特殊的对象,对于每一个请求,它都是唯一的。在一个请求中,多个方法都有权访问g
存储的数据。连接被保存在g
中,如果在同一个请求中,get_db
方法被调用第二次,那么连接将会被重用而不是重新创建一个新的连接。
current_app是另一个特殊的对象,它指向当前处理这个请求的Flask应用。由于你使用的是应用程序工厂,因此在编写其余代码时没有应用程序对象,current_app
就是这个应用程序对象。当应用已经被创建开始处理请求时,get_db
将会被调用,这里使用current_app
获取配置信息。
sqlite3.connect()与指向DATABASE
配置键的文件建立起一个数据库连接。此文件当前还不存在,直到你初始化数据库之后才会出现。
sqlite3.Row告诉连接返回像字典数据形式的行。这样可以通过列名进行访问数据。
close_db
函数检查是否在g.db
对象中创建出来的连接是否存在。如果连接存在,它就关闭这个连接。你将在应用工厂中告诉你的应用有关close_db
函数,以便在每个请求之后它能够被调用。
1.3.2.创建表
在SQLite数据中,数据是存储在表或列中。在存储和查看数据之前,你需要先创建表。Flaskr将在user
表中存储用户信息,在post
表中存储请求信息。创建包含创建空表sql语句的文件:
flaskr/schema.sql
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
);
CREATE TABLE post (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
body TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES user (id)
);
在db.py
文件中添加运行这些sql命令的Python函数。
flaskr/db.py
def init_db():
db = get_db()
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
@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.')
open_resource()打开一个相对于flaskr
目录的文件。这个方法非常有用——当你不知道你项目路径时,可以使用该方法获取对应的项目文件。get_db
方法返回一个用于执行sql命令的数据库连接。
click.command()定义了一个名为init-db
的命令行命令。该命令行的功能主要是调用上面定义的init_db
函数并给用户展示一个数据库初始化成功的信息。你可以阅读 Command Line Interface来了解如何编写命令。
1.3.3.注册到应用中
close_db
和init_db_command
函数需要被注册到应用实例中,否则它们不能在应用中使用。然而由于你使用了工厂函数,当你在写这些函数时,应用实例你还获取不到。取而代之的方式是写一个提出申请并进行注册的函数。
flaskr/db.py
def init_app(app):
app.cli.add_command(init_db_command)
app.teardown_appcontext(close_db)
app.teardown_appcontext()告诉Flask当返回响应时调用注册的方法进行清理。
app.cli.add_command()添加一个新的能被flask
命令调用的命令。
在工厂中导入和调用该函数。在工厂函数之后,返回app之前编写新的代码:
flaskr/__init__.py
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
1.3.4.初始化数据库文件
现在,init-db
命令已经注册到app中了,你可以使用flask
命令调用它,类似与前面说的run
命令。
注意:
如果你还运行着前面的服务,你要么停止该服务,要么就新启一个命令行终端。如果你新启一个命令行终端,记得切换到项目目录,并且激活Activate the environment这里的环境。你同样需要设置前面提到的FLASK_APP
和FLASK_ENV
这两个环境变量。
运行init-db
命令:
flask init-db
Initialized the database.
现在,在你工程的实例目录下应该有一个名为flaskr.sqlite
的文件。
看得累了,敲代码去了,有空继续更