Flask项目配置

创建项目

flask 项目不能像 django 那样通过命令行创建,所以直接在 pycharm 中新建 Flask 项目。

假如我们创建了一个名为 Demo 的项目,那么创建好的项目目录如下所示:

1
2
3
4
Demo
- static
- templates
- app.py

只有两个文件夹和一个 py 文件,真不愧是轻量级框架。

  • static:存放静态资源,如 css,js
  • templates:存放模板,类似 django
  • app.py:项目启动文件

然后我们就可以启动项目了。在启动项目之前,需要设置 Flask 的环境变量,打开终端,执行以下指令:

1
$env:FLASK_APP=app.py

app.py 就是项目的入口文件,名字依个人而异。

然后启动项目:

1
flask run

项目配置

创建“app”

类似于 Django,我们需要创建一个“app”用来存放各个模块的视图函数、路由配置、模型文件等。

在根目录下创建包 “webapp”,然后在 webapp 下创建所需的模块,再在每个模块下创建 views.py 存放视图函数,创建 models.py 存放数据库模型。

目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Demo
- static
- templates
- webapp
- __init__.py
- user
- __init__.py
- views.py
- models.py
- order
- __init__.py
- views.py
- models.py
...
- app.py

webapp 下的 init.py 文件主要用于创建 flask 应用并加载配置,如 MySQL、redis等。

user 和 order 下的 init.py 文件用于创建蓝图对象,然后在 views.py 文件中导入对象并使用。

user/views.py

1
2
3
4
5
from . import userApp

@userApp.route('/user')
def login():
return 'silence'

user/init.py

1
2
3
4
5
from flask import Blueprint

userApp = Blueprint('user', __name__)

from .view import * # 写在末尾,不然会因循环导入报错

创建配置文件

在根目录新建 settings.py 文件,我们可以在其中自定义配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Config:
# 密钥,用于 session 加密
SECRET_KEY = 'Sm9obiBTY2hyb20ga2lja3MgYXNz'
# 数据库连接格式
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://user:password@localhost:3306/databasename?charset=utf8"


# 发展环境配置
class DevelopmentConfig(Config):
DEBUG = True


# 生产环境配置
class ProductionConfig(Config):
DEBUG = False


config = {
'development': DevelopmentConfig,
'production': ProductionConfig
}

配置项是需要加载到项目中的,可以在 app.py 中加载,也可以在 webapp/init.py 中加载。

项目默认在 app.py 中创建 Flask 实例,我们也可以将这部分代码封装到一个函数中,还可以添加更多的其它功能。

在 webapp/init.py 中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask
from settings import config


def createApp():
# 创建 app
app = Flask(__name__)

# 选择配置类
Config = config['development']

# 加载配置
app.config.from_object(Config)

# 注册蓝图
# 在使用前 import,防止循环导入
from .cart.view import cartApp
app.register_blueprint(userApp)

from .user.view import userApp
app.register_blueprint(cartApp)

return app

然后将注册好的 app 导入 app.py 文件中:

1
from webapp import createAppapp = createApp()if __name__ == '__main__':    app.run()

配置数据库

Flask-SQLAlchemy 是一款适用于 Flask 的数据库插件,它支持包含 MySQL、PostgreSQL 和 SQLite 在内的很多数据库软件。

我们可以在开发的时候使用简单易用且无需另起服务的 SQLite(直接以 db 文件保存在项目中),需要部署应用到生产服务器上时,则选用更健壮的 MySQL 或 PostgreSQL 服务。

1. 安装

flask-sqlalchemy 用于连接数据库:

1
pip install flask-sqlalchemy

flask-migrate 用于迁移数据库:

1
pip install flask-migrate
2. 配置 settings.py

在 settings.py 中添加如下代码:

1
import osbasedir = os.path.abspath(os.path.dirname(__file__))class Config:    # 密钥,用于 session 加密    SECRET_KEY = 'Sm9obiBTY2hyb20ga2lja3MgYXNz'# 发展环境配置class DevelopmentConfig(Config):    DEBUG = True    # 数据库连接格式    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'app.db')    # 数据发生变更是否发信号给应用    SQLALCHEMY_TRACK_MODIFICATIONS = False# 生产环境配置class ProductionConfig(Config):    DEBUG = False    # 数据库连接格式    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://user:password@localhost:3306/databasename?charset=utf8"

os.environ.get 可以获取本机的用户环境变量,一些比较机密的数据可以放在环境变量里面,仅对自己可见。or 的作用是如果没有定义该环境变量,则选择后面的值。

当然,发展环境也可以用 mysql 数据库。

3. 配置 app/init.py

在 webapp/init.py 文件中添加如下代码:

1
from flask_sqlalchemy import SQLAlchemyfrom flask_migrate import Migrate# 创建数据库连接对象db = SQLAlchemy()# 创建数据库迁移对象migrate = Migrate()def createApp():    ...    # 初始化数据库连接对象    db.init_app(app)    # 初始化数据库迁移对象    migrate.init_app(app, db)    ...
4. 创建数据库模型

在 user/models.py 中添加如下代码:

1
from webapp import dbclass User(db.Model):    __tablename__ = "user"  # 设置表名    id = db.Column(db.Integer, autoincrement=True, primary_key=True)    username = db.Column(db.String(50), unique=True, nullable=False)    email = db.Column(db.String(120), unique=True, nullable=False)    password = db.Column(db.String(20), nullable=False)

在 cart/models.py 中添加如下代码:

1
from webapp import dbclass Cart(db.Model):    __tablename__ = "cart"  # 设置表名    id = db.Column(db.Integer, autoincrement=True, primary_key=True)    user = db.Column(db.Integer, db.ForeignKey(‘user.id’)) # 外键 (‘表名.id’)    shopname = db.Column(db.String(200), nullable=False)    price = db.Column(db.Float(2), nullable=False)    date = db.Column(db.DateTime, nullable=False)
生成数据库

先初始化迁移文件:

1
flask db init

会发现根目录下多了一个 migrations 文件夹,就是生成的迁移文件。

然后要创建数据表,有两种方法:

  1. 在项目中的某个文件导入模型类或实例化模型类之后,在终端执行

    1
    flask db migrateflask db  upgrade
  2. 不需要事先在项目中导入模型类,打开终端,进入 shell:flask shell,然后执行

    1
    >>> from webapp import db>>> from webapp.user.models import User>>> from webapp.cart.models import Cart>>> db.create_all()>>> quit()

    此方法需要在 shell 中导入要创建的模型类。

之后如果更改了数据库,用以上两种方法即可。

使用数据库

在 user/view.py 中添加如下代码:

1
from .models import *@userApp.route('/login', methods=['post'])def login():    data = request.get_json()    username = data['username']    password = data['password']    email = data['email']    user = User(username=username, password=password, email=email)    db.session.add(user) # 添加数据    db.session.commit() # 提交更改    return jsonify({'username': username, 'password': password})

关于更多 Falsk-SQLAlchemy 对数据库的操作,请看 Falsk-SQLAlchemy


跨域

安装 flask-cors:

1
pip install flask-cors

在入口文件 app.py 中添加如下代码:

1
from flask_cors import CORSCORS(app, ssupports_credentials=True)

我们还可以规定 origins(请求源)、methods(请求方法)、allow_headers(允许的请求头)supports_credentials(是否支持 cookie)。


配置 redis
安装 redis 支持包
1
pip install flask-redis
配置 settings.py

在 settings.py 文件中添加如下代码:

1
REDIS_URL = "redis://:password@localhost:6379/0"
配置 webapp/init.py
1
from flask_redis import FlaskRedis# 创建 redis 对象redis_client = FlaskRedis()def createApp():    ...    # 初始化 redis 对象    redis_client.init_app(app)    ...

接下来就可以通过 redis-client 操作 redis 数据库了。


flask 用 redis 缓存 session
安装 flask-session
1
pip install flask-session
配置 settings.py

添加如下内容:

1
# 配置 session# 存储方式SESSION_TYPE = 'redis'# session 是否长期有效,如为 False 则关闭浏览器 session 失效SESSION_PERMANENT = True# session 如果设定为长期有效则设定 session 生命周期,单位是秒(默认为31天)PERMANENT_SESSION_LIFETIME = 60 * 60 * 24# 密钥,用于 session 加密SECRET_KEY = 'Sm9obiBTY2hyb20ga2lja3MgYXNz'# 是否对发送到浏览器上 session 的 cookie 值进行加密SESSION_USE_SIGNER = True# 保存 session 对象的键的前缀SESSION_KEY_PREFIX = 'session:'# 配置redis服务器参数,默认为 0 数据库SESSION_REDIS = StrictRedis(    host='localhost',    port=6379,    db=1,    password='123456')
配置 webapp/init.py
1
from flask_session import Session# 创建 session 对象session = Session()def createApp():    ...    # 初始化 redis 对象    session.init_app(app)    ...
使用 session

我们虽然使用到了 flask-session,但它仅用来配置 session,使用 session 时还是要用 flask 模块中 session:

user/view.py

1
from flask import session@userApp.route('/register', methods=['post', 'get'])def login():    # 存    session[key] = value        # 取    val = session.get[key]    if val is None:        return 'None'

用 redis 做 cache 缓存

当你的应用变慢的时候,可以考虑加入缓存。至少这是最简单的加速方法。缓存有什 么用?假设有一个函数耗时较长,但是这个函数在五分钟前返回的结果还是正确的, 那么我们就可以考虑把这个函数的结果在缓存中存放一段时间,当再次请求数据的时候直接从缓存中读取。

安装 flask-cache
1
pip install flask-cache
配置 settings.py
1
CACHE_TYPE = 'redis'CACHE_REDIS_HOST = 'localhost'CACHE_REDIS_PORT = 6379CACHE_REDIS_DB = '2'CACHE_REDIS_PASSWORD = '123456'CACHE_DEFAULT_TIMEOUT = 60 # 过期时间
配置 webapp/init.py
1
from flask_cache import Cache# 创建 cache 对象cache = Cache()def createApp():    ...    # 初始化 cache 对象    cache.init_app(app)    ...
使用 cache
1
from webapp import cachecache.set(key, value)  # 添加cache.get(key)  # 获取cache.delete(key) # 删除cache.clear() # 清除所有缓存

在 cart/view.py 文件中添加如下代码:

1
from webapp import cache@cartApp.route('/cart', methods=['get'])@cache.cached(timeout=60, key_prefix='cart_index')def getCartInfo():    ...

使用装饰函数 @cache.cached 修饰视图函数,表示将视图函数的返回结果缓存到 redis 中。并且 @cache.cached 必须在 @cartApp.route 之后

@cache.cached 有两个参数,第一个表示过期时间,单位为秒,第二个表示保存在 redis 中的键的前缀。这个前缀名在删除缓存的时候可以用到。

这种方法适用于对所有用户都相同的页面数据进行缓存。

如果要针对每个用户单独进行缓存,可将用户的信息作为 cache 键的一部分,手动进行缓存:

1
from webapp import cache@cartApp.route('/cart', methods=['get'])def getCartInfo():    username = session.get('username')    if cache.get('cart_'+username) is not None:        data = cache.get('cart_'+username)    else:        data = []        ...        key = 'cart_' + username        cache.set(key, data)    ...

当一个视图函数的返回结果发生改变时,缓存也应该进行更新。更新的方法就是在结果发生改变的地方将缓存删除,那么当用户再次请求的时候就会生成新的缓存。


flask 邮件
安装 flask-mail
1
pip install flask-mail
配置 settings.py
1
# 配置邮件(网易邮箱)    MAIL_SERVER = 'smtp.163.com'    MAIL_PORT = 465    MAIL_USE_SSL = True # 安全协议    MAIL_USERNAME = 'silence@163.com' # 发信服务器的用户名    MAIL_PASSWORD = '' # 授权码    MAIL_DEFAULT_SENDER = ('Silence', 'silence@163.com') # 默认发送人(姓名,邮箱地址)
配置 webapp/init.py
1
from flask_mail import Mail# 创建 mail 对象mail = Mail()def createApp():    ...    # 初始化 mail 对象    mail.init_app(app)    ...
发送邮件

在 user/view.py 中添加如下代码:

1
from flask_mail import Messagefrom webapp import mail@userApp.route('/register', methods=['post', 'get'])def register():    ...    # 邮件主题    subject = '账号激活'    # 接收者    recipients = [email]    # 邮件内容(html)    html = '点击链接激活邮箱: <a href="http://127.0.0.1:5000/check/%d">xxxxxxxxx</a>' %(user_id)    # 创建邮件内容    message = Message(subject=subject, recipients=recipients, html=html)    # 发送邮件    mail.send(message)    ...    # 用户点击链接访问此 url@userApp.route('/check/<id>')def chackid(id):    return str(id)

celery 任务队列

celery 是异步任务队列,可以将一些比较耗时的操作(发送邮件)交给它来异步处理,这样用户不需要一直等待,以提高用户体验。

安装 celery
1
pip install celery
配置 settings.py
1
# 配置 celery# 消息中间件的保存位置CELERY_BROKER_URL = 'redis://:123456@192.168.239.130:6379/3'# 返回结果的保存位置CELERY_RESULT_BACKEND = 'redis://:123456@192.168.239.130:6379/3'# 任务过期时间CELERY_TASK_RESULT_EXPIRES = 120
在 webapp/init.py 中创建 celery 对象
1
from celery import Celeryfrom settings import Config			   # app 名celery = Celery(__name__, broker=Config.CELERY_BROKER_URL, backend=Config.CELERY_RESULT_BACKEND)def createApp():    ...    # 完善 celery 配置    celery.conf.update(app.config)    ...
创建任务

新建 tasks.py 文件,我们用 celery 来发送邮件,在其中添加如下内容:

1
from webapp import celery, mail, createAppfrom flask_mail import Message@celery.task()def send_email(user_id, email):    app = createApp()    mail.init_app(app)    # 创建应用上下文    with app.app_context():        # 邮件主题        subject = '账号激活'        # 接收者        recipients = [email]        # 邮件内容(html)        html = '点击链接激活邮箱: <a href="http://127.0.0.1:5000/check/%d">xxxxxxxxx</a>' % user_id        message = Message(subject=subject, recipients=recipients, html=html)        mail.send(message)

通过 @celery.task() 装饰器来声明这是一个 celery 任务。

关于 flask 应用上下文的介绍,请看 Flask 应用上下文

使用任务

在 user/view.py 文件中添加如下内容:

1
from tasks import send_email@userApp.route('/register', methods=['post', 'get'])def register():    ...    send_email.delay(user.id, email)       ...

celery 开启任务的方法:

  • ```
    delay(*args, **kwargs)

    1
    2
    3
    4
    5

    直接发送一个任务消息,其传入的参数就是任务函数的参数。

    - ```
    apply_async(countdown=60, expires=120)

    从现在起一分钟执行,但在两分钟后过期。

开启 celery 服务
  • Windows:

    1
    pip install eventletcelery -A tasks worker -l info -P eventlet
  • Linux:

    1
    celery -A tasks worker -l info