简介
Flask 是 Python 社区中开发 Web 应用最火热的框架之一,不同于 Django 陡峭的学习曲线,个人感觉 Flask 非常好上手,且社区生态丰富,有很多成熟的扩展可以拿来直接安装使用。 Flask 框架自身集成了基于 Jinja 的模板语言,使其可以完成前后端的所有开发,但现在大部分的 Web 应用都是前后端分离,所以本文将使用 Flask RESTful 扩展实现一个纯后端的 API 服务。 通过本文可以学习到以下内容:
- 使用 Flask + Flask RESTful 搭建 API 应用并使用 Blueprint(蓝图) 管理 API;
- 使用 Flask-SQLAlchemy 扩展实现 ORM 操作 MySQL 数据库;
- 基于 JWT 验证实现注册、登录以及登出接口;
- 实现一个最基本的列表获取接口;
- 解决跨域问题;
- 使用 Docker 部署该应用。
在正式开始之前,请确保你已经安装了 Python,并且对 Python 有一定了解。
初始化项目
首先我们新建一个空文件夹,作为项目的根目录。进入到项目根目录后创建一个虚拟环境:
# MacOS/Linux
mkdir myproject
cd myproject
python3 -m venv .venv
# Windows
mkdir myproject
cd myproject
py -3 -m venv .venv
激活虚拟环境
# MacOS/Linux
. .venv/bin/activate
# Windows
.venv\Scripts\activate
安装 Flask、Flask RESTful 以及 python-dotenv,最后一个包用来获取我们在项目中定义的环境变量。
pip install Flask flask-restful python-dotenv
按照惯例,我们先简单实现一个接口,验证下我们最基础的包是否安装完成。 首先在项目根目录下新建一个 app
文件夹,在 app
下新建一个 __init__.py
文件,在这个文件中,我们定义一个测试用的接口。
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
我们先引入了 Flask
和 flask_restful 中的 Resource
和 Api
,然后我们使用 Flask()
初始化一个 Flask 应用实例赋值给 app
,传入的 __name__
则是模块名 "app"
,然后再使用 Api(app)
初始化一个 flask_restful 实例赋值给 api
。 接下来我们定义了 HelloWorld
这个类,它继承于 Resource
类。这个类中定义一个名为 get
的函数,它返回一个固定的 JSON 为{'hello': 'world'}
。
最后我们使用 api.add_resource(HelloWorld, '/')
去注册接口,并指定了访问路由,当访问的接口路径为 "/"
且请求方式为 GET
时,就会调用该类中定义好的 get()
函数处理。 你可能已经猜到了,在以 Resource
类为基类的派生类中,就是我们定义不同 HTTP 请求方式的地方,所以在这个类中,你还可以定义 post
,put
,delete
等函数。 接下来,我们在项目根目录中新建一个 run.py
文件:
from app import app
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
这是一个启动文件,你可以直接在控制台中使用 python run.py
执行,或是和我一样,在项目根目录下新建一个 .env
文件用来存放环境变量:
FLASK_ENV=development # 当前环境
FLASK_DEBUG=True # 开启 debug mode
FLASK_APP=run.py # flask项目入口文件
上面这些环境变量的命名方式都是 Flask 规定的,这样指定环境变量的好处就是我们可以通过控制台执行 flask run
命令来启动服务。 需要注意的是,如果你通过 flask run
命令来启动服务,那么 Flask 的配置会默认以环境变量为准,并且会忽略 run.py
中的配置项。 现在我们启动项目后,看到以下信息就说明服务启动成功了。
- Serving Flask app 'run.py'
- Debug mode: on
- Running on http://127.0.0.1:5000 Press CTRL+C to quit
- Restarting with stat
- Debugger is active!
- Debugger PIN: xxx-xxx-xxx
现在你可以直接使用浏览器访问 http://127.0.0.1:5000/
或使用 Apifox 等接口调试工具来进行测试,看看是否会得到返回的 {'hello': 'world'}
JSON 字符串。
连接数据库
要连接数据库,需要先安装 Flask-SQLAlchemy 、Flask-Migrate 和 pymysql 这三个扩展包,Flask-SQLAlchemy 用来连接并操作数据库,Flask-Migrate 是一个数据库迁移插件,用来同步数据库的更改。最后因为我们要连接的是 MySQL 数据库,所以需要安装一个 pymysql 包。
pip install Flask-SQLAlchemy Flask-Migrate pymysql
接下来我们修改一下我们项目的目录结构,让我们项目的可扩展性更强。
/
├── .venv/
├── app/
│ └── api/ # api 接口模块
│ └── __init__.py # 注册以及生成蓝图
│ └── common/ # 公共方法
│ └── models/ # 模型
│ └── resources/ # 接口
│ └── schema/ # 校验
│ └── __init__.py # 整个应用的初始化
│ └── config.py # 配置项
│ └── manage.py # 数据库迁移工具管理
├── .env # 环境变量
├── run.py # 入口文件
这样修改我们的项目结构,可以让我们配合 Flask 提供的 Blueprint (蓝图) 对接口进行模块化管理和开发,有助于提高我们项目的可扩展性和可维护性。 接下来我们先配置数据库连接,首先你要确保你有可用的 MySQL 数据库,然后在 /app/config.py
中添加如下代码:
import os
# 数据库相关配置
# 建议在本地根目录下新建 .env 文件维护敏感信息配置项更安全
# 用户名
USERNAME = os.getenv('MYSQL_USER_NAME')
# 密码
PASSWORD = os.getenv('MYSQL_USER_PASSWORD')
# 地址
HOSTNAME = os.getenv('MYSQL_HOSTNAME')
# 端口
PORT = os.getenv('MYSQL_PORT')
# 数据库名称
DATABASE = os.getenv('MYSQL_DATABASE_NAME')
# 固定格式 不用改
DIALECT = 'mysql'
DRIVER = 'pymysql'
class Config(object):
DEBUG = False
TESTING = False
SECRET_KEY = os.getenv('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?".format(DIALECT, DRIVER, USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
SQLALCHEMY_ECHO = True
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = ''
class DevelopmentConfig(Config):
DEBUG = True
class TestingConfig(Config):
TESTING = True
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'testing': TestingConfig,
'default': DevelopmentConfig,
}
然后我们在 .env
文件中新增下面的环境变量:
# ...
SECRET_KEY=b'#q)\\x00\xd6\x9f