创建项目
flask 项目不能像 django 那样通过命令行创建,所以直接在 pycharm 中新建 Flask 项目。
假如我们创建了一个名为 Demo 的项目,那么创建好的项目目录如下所示:
1 2 3 4
| Demo - static - templates - app.py
|
只有两个文件夹和一个 py 文件,真不愧是轻量级框架。
- static:存放静态资源,如 css,js
- templates:存放模板,类似 django
- app.py:项目启动文件
然后我们就可以启动项目了。在启动项目之前,需要设置 Flask 的环境变量,打开终端,执行以下指令:
1 2
| $env:FLASK_APP=app.py $env:FLASK_ENV=development
|
linux 环境:
1 2
| export FLASK_APP=app.py export FLASK_ENV=development
|
app.py 就是项目的入口文件,名字依个人而异。
然后启动项目:
项目配置
创建“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: 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 = Flask(__name__) Config = config['development'] app.config.from_object(Config) from .cart.view import cartApp app.register_blueprint(userApp) from .user.view import userApp app.register_blueprint(cartApp)
return app
|
然后将注册好的 app 导入 app.py 文件中:
1 2 3 4 5 6
| from webapp import createApp
app = 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config: 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate
db = SQLAlchemy()
migrate = Migrate()
def createApp(): ... db.init_app(app) migrate.init_app(app, db) ...
|
4. 创建数据库模型
在 user/models.py 中添加如下代码:
1 2 3 4 5 6 7 8 9
| from webapp import db
class 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 2 3 4 5 6 7 8 9 10
| from webapp import db
class Cart(db.Model): __tablename__ = "cart" id = db.Column(db.Integer, autoincrement=True, primary_key=True) user = db.Column(db.Integer, db.ForeignKey(‘user.id’)) shopname = db.Column(db.String(200), nullable=False) price = db.Column(db.Float(2), nullable=False) date = db.Column(db.DateTime, nullable=False)
|
生成数据库
先初始化迁移文件:
会发现根目录下多了一个 migrations 文件夹,就是生成的迁移文件。
然后要创建数据表,有两种方法:
在项目中的某个文件导入模型类或实例化模型类之后,在终端执行
1
| flask db migrateflask db upgrade
|
不需要事先在项目中导入模型类,打开终端,进入 shell:flask shell
,然后执行
1 2 3 4 5
| >>> 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 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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:
在入口文件 app.py 中添加如下代码:
1 2 3
| from flask_cors import CORS
CORS(app, ssupports_credentials=True)
|
我们还可以规定 origins
(请求源)、methods
(请求方法)、allow_headers
(允许的请求头)supports_credentials
(是否支持 cookie)。
配置 redis
安装 redis 支持包
配置 settings.py
在 settings.py 文件中添加如下代码:
1
| REDIS_URL = "redis://:password@localhost:6379/0"
|
配置 webapp/init.py
1 2 3 4 5 6 7 8 9 10
| from flask_redis import FlaskRedis
redis_client = FlaskRedis()
def createApp(): ... redis_client.init_app(app) ...
|
接下来就可以通过 redis-client 操作 redis 数据库了。
flask 用 redis 缓存 session
安装 flask-session
1
| pip install flask-session
|
配置 settings.py
添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
SESSION_TYPE = 'redis'
SESSION_PERMANENT = True
PERMANENT_SESSION_LIFETIME = 60 * 60 * 24
SECRET_KEY = 'Sm9obiBTY2hyb20ga2lja3MgYXNz'
SESSION_USE_SIGNER = True
SESSION_KEY_PREFIX = 'session:'
SESSION_REDIS = StrictRedis(host='localhost', port=6379, db=1, password='123456')
|
配置 webapp/init.py
1 2 3 4 5 6 7 8 9 10
| from flask_session import Session
session = Session()
def createApp(): ... session.init_app(app) ...
|
使用 session
我们虽然使用到了 flask-session,但它仅用来配置 session,使用 session 时还是要用 flask 模块中 session:
user/view.py
1 2 3 4 5 6 7 8 9 10
| 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
配置 settings.py
1 2 3 4 5 6
| CACHE_TYPE = 'redis' CACHE_REDIS_HOST = 'localhost' CACHE_REDIS_PORT = 6379 CACHE_REDIS_DB = '2' CACHE_REDIS_PASSWORD = '123456' CACHE_DEFAULT_TIMEOUT = 60
|
配置 webapp/init.py
1 2 3 4 5 6 7 8 9 10
| from flask_cache import Cache
cache = Cache()
def createApp(): ... cache.init_app(app) ...
|
使用 cache
1 2 3 4 5 6
| from webapp import cache
cache.set(key, value) cache.get(key) cache.delete(key) cache.clear()
|
在 cart/view.py 文件中添加如下代码:
1 2 3 4 5 6
| 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 2 3 4 5 6 7 8 9 10 11 12 13
| 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
配置 settings.py
1 2 3 4 5 6 7
| 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 2 3 4 5 6 7 8 9 10
| from flask_mail import Mail
mail = Mail()
def createApp(): ... mail.init_app(app) ...
|
发送邮件
在 user/view.py 中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from flask_mail import Message from webapp import mail
@userApp.route('/register', methods=['post', 'get']) def register(): ... subject = '账号激活' recipients = [email] 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) ...
@userApp.route('/check/<id>') def chackid(id): return str(id)
|
celery 任务队列
celery 是异步任务队列,可以将一些比较耗时的操作(发送邮件)交给它来异步处理,这样用户不需要一直等待,以提高用户体验。
安装 celery
配置 settings.py
1 2 3 4 5 6 7
|
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 2 3 4 5 6 7 8 9 10 11
| from celery import Celery from settings import Config
celery = Celery(__name__, broker=Config.CELERY_BROKER_URL, backend=Config.CELERY_RESULT_BACKEND)
def createApp(): ... celery.conf.update(app.config) ...
|
创建任务
新建 tasks.py 文件,我们用 celery 来发送邮件,在其中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from webapp import celery, mail, createApp from 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 = '点击链接激活邮箱: <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 2 3 4 5 6 7
| from tasks import send_email
@userApp.route('/register', methods=['post', 'get']) def register(): ... send_email.delay(user.id, email) ...
|
celery 开启任务的方法:
直接发送一个任务消息,其传入的参数就是任务函数的参数。
1
| 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
|