这个应用使用 SQLite 数据库来存储用户。Python 的 sqlite3 模块提供了对 SQLite 的支持。
SQLite 很方便,但是并发请求同时请求写入服务器就会变得很慢,因为每个写入按次序发生。小的应用可以忽略,但是大的应用就可能会让你考虑换一个数据库了。
连接数据库
使用 SQLite 首先得连接,在 Web 应用中,连接就跟 request 相联系,他会在处理 request 请求某个时刻被创建,在 response 被发送之前关闭。
#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是一个对象,它对每个 request 是唯一的,被用来在请求的时候存储多个函数得到的数据。这个链接就是被存储在g中。
current_app 是指向 flask 应用的特殊对象
sqlite3.connect() 建立一个 DATABASE 配置指向的文件的连接
sqlite3.Row 让连接返回的行能够像字典一样进行操作,这样就可以通过名称获得列
创建表
SQLite 中数据是存在表和列中的,为此需要创建2张表,分别是 user 和 post
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)
);
添加 python 函数以便运行 SQL 命令
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 返回数据库连接,用来执行从文件中读取的命令
click.command 定义一个叫做 init-db 的命令行命令,它会调用 init-db 方法并且列出一些成功的信息。
注册应用
close_db 和 init_db_command 方法需要注册到应用程序中否则不会被应用使用
db.py
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
app.teardown_appcontext() 告诉调用那个方法
app.cli.add_command() 添加了一个新的可以被调用的命令
flaskr/__init__.py
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
初始化数据库文件
init-db 注册了以后就可以被 flask 命令调用了 ,运行 init-db 命令
flask init-db
Initialized the database.
于是就会有一个 flaskr.sqlite 文件在 instance 文件中。