创建项目
flask  项目不能像 django 那样通过命令行创建,所以直接在 pycharm 中新建 Flask 项目。
假如我们创建了一个名为 Demo 的项目,那么创建好的项目目录如下所示:
| 12
 3
 4
 
 | Demo- static
 - templates
 - app.py
 
 | 
只有两个文件夹和一个 py 文件,真不愧是轻量级框架。
- static:存放静态资源,如 css,js
- templates:存放模板,类似 django
- app.py:项目启动文件
然后我们就可以启动项目了。在启动项目之前,需要设置 Flask 的环境变量,打开终端,执行以下指令:
| 12
 
 | $env:FLASK_APP=app.py$env:FLASK_ENV=development
 
 | 
linux 环境:
| 12
 
 | export FLASK_APP=app.pyexport FLASK_ENV=development
 
 | 
app.py 就是项目的入口文件,名字依个人而异。
然后启动项目:
项目配置
创建“app”
类似于 Django,我们需要创建一个“app”用来存放各个模块的视图函数、路由配置、模型文件等。
在根目录下创建包 “webapp”,然后在 webapp 下创建所需的模块,再在每个模块下创建 views.py 存放视图函数,创建 models.py 存放数据库模型。
目录结构如下:
| 12
 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
| 12
 3
 4
 5
 
 | from . import userApp
 @userApp.route('/user')
 def login():
 return 'silence'
 
 | 
user/init.py
| 12
 3
 4
 5
 
 | from flask import Blueprint
 userApp = Blueprint('user', __name__)
 
 from .view import *
 
 | 
创建配置文件
在根目录新建 settings.py 文件,我们可以在其中自定义配置:
| 12
 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 中添加如下代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | from flask import Flaskfrom 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 文件中:
| 12
 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 中添加如下代码:
| 12
 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 文件中添加如下代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | 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 中添加如下代码:
| 12
 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 中添加如下代码:
| 12
 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,然后执行
 | 12
 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 中添加如下代码:
| 12
 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 中添加如下代码:
| 12
 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
| 12
 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
添加如下内容:
| 12
 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
| 12
 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
| 12
 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
| 12
 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
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | from flask_cache import Cache
 
 cache = Cache()
 
 def createApp():
 ...
 
 cache.init_app(app)
 ...
 
 | 
使用 cache
| 12
 3
 4
 5
 6
 
 | from webapp import cache
 cache.set(key, value)
 cache.get(key)
 cache.delete(key)
 cache.clear()
 
 | 
在 cart/view.py 文件中添加如下代码:
| 12
 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 键的一部分,手动进行缓存:
| 12
 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
| 12
 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
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | from flask_mail import Mail
 
 mail = Mail()
 
 def createApp():
 ...
 
 mail.init_app(app)
 ...
 
 | 
发送邮件
在 user/view.py 中添加如下代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | from flask_mail import Messagefrom 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
| 12
 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 对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | from celery import Celeryfrom 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 来发送邮件,在其中添加如下内容:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 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 = '点击链接激活邮箱: <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 文件中添加如下内容:
| 12
 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
 |