1.Flask教程

源地址: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()创建一个简单的路由,这样你可以在进入教程其他部分之前看到一个可运行的应用。在这个例子中,应用创建了一个指向/hellourl的连接和一个返回字符串'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_dbinit_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_APPFLASK_ENV这两个环境变量。

        运行init-db命令:

flask init-db
Initialized the database.

现在,在你工程的实例目录下应该有一个名为flaskr.sqlite的文件。


看得累了,敲代码去了,有空继续更

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容