创建项目
- 创建git忽略文件, 并生成项目的本地仓库
- 项目中创建四个包app、 mp、 mis、 common, 分别对应三个web应用: 前台程序、媒体端程序、后台程序, 以及各web应用需要使用的公共内容
定义工厂函数
- 在 app包中创建 settings包, 用于存放项目配置, 并在 settings包中创建 config文件并设置默认配置
# app/settings/config.py
class DefaultConfig:
"""默认配置"""
pass
config_dict = {
'dev': DefaultConfig
}
- 在 common包中创建 utils包, 并在 utils包中创建 constants文件, 用于存放所有常量
- 在 constants文件中 定义常量记录隐私配置使用的环境变量名
# common/utils/constants.py
EXTRA_ENV_COINFIG = 'ENV_CONFIG' # 额外配置对应的环境变量名
- 在 app包的初始化文件中完成以下两步
定义工厂函数
添加 common路径
# app/__init__.py
from flask import Flask
from os.path import *
import sys
# 将common路径加入模块查询路径
BASE_DIR = dirname(dirname(abspath(__file__)))
sys.path.insert(0, BASE_DIR + '/common')
from app.settings.config import config_dict
from utils.constants import EXTRA_ENV_COINFIG
def create_flask_app(type):
"""创建flask应用"""
# 创建flask应用
app = Flask(__name__)
# 根据类型加载配置子类
config_class = config_dict[type]
# 先加载默认配置
app.config.from_object(config_class)
# 再加载额外配置
app.config.from_envvar(EXTRA_ENV_COINFIG, silent=True)
# 返回应用
return app
def create_app(type):
"""创建应用 和 组件初始化"""
# 创建flask应用
app = create_flask_app(type)
# 组件初始化
return app
项目运行
在 app包中创建 main文件, 在其中完成以下两步
- 通过工厂函数创建flask应用对象
- 定义根路由, 用于获取项目定义的所有路由
# app/main.py
from app import create_app
from flask import jsonify
# 创建web应用
app = create_app('dev')
@app.route('/')
def route_map():
"""定义根路由: 获取所有路由规则"""
return jsonify({rule.endpoint: rule.rule for rule in app.url_map.iter_rules()})
- 右键运行 main文件, 生成程序默认配置
- 修改程序配置, 设置环境变量、解释器参数
- 修改程序默认配置生成的项目目录, 默认为主文件的上一级
- 运行程序, 测试根路由
配置数据库
设置相关配置
在 config文件中设置 MYSQL 和 REDIS 的相关配置
# app/settings/config.py
class DefaultConfig:
"""默认配置"""
# mysql配置
SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@192.168.105.140:3306/hm_topnews' # 连接地址
SQLALCHEMY_TRACK_MODIFICATIONS = False # 是否追踪数据变化
SQLALCHEMY_ECHO = False # 是否打印底层执行的SQL
# redis配置
REDIS_HOST = '192.168.105.140' # ip
REDIS_PORT = 6381 # 端口
...
通过 pycharm数据库管理工具/ssh工具 在centos虚拟机中创建相应的mysql数据库
SQLAlchemy组件初始化
在 app包的初始化文件中:
- 创建SQLAlchemy组件对象
- 定义函数register_extensions 对 SQLAlchemy 进行组件初始化
# app/__init__.py
...
from flask_sqlalchemy import SQLAlchemy
# sqlalchemy组件对象
db = SQLAlchemy()
def register_extensions(app):
"""组件初始化"""
# SQLAlchemy组件初始化
from app import db
db.init_app(app)
...
def create_app(type):
"""创建应用 和 组件初始化"""
# 创建flask应用
app = create_flask_app(type)
# 组件初始化
register_extensions(app)
return app
Redis组件初始化
- redis操作使用第三方包redis-py, 安装 pip install redis==2.10
- 在 app包的初始化文件中
创建Redis操作对象
在函数register_extensions 中对Redis进行组件初始化
# app/__init__.py
...
from redis import StrictRedis
...
# redis数据库操作对象
redis_client = None # type: StrictRedis
def register_extensions(app):
"""组件初始化"""
...
# redis组件初始化
global redis_client
# 创建redis数据库客户端
redis_client = StrictRedis(host=app.config['REDIS_HOST'], port=app.config['REDIS_PORT'], decode_responses=True)
# decode_responses:从redis取出的数据是bytes类型,我们还要对其进行解码,设置其值为true会自动帮我们进行解码
配置模块化
创建功能包
- 在 app包中创建 resources包, 用于包含各功能模块的视图
- 在 resources包中创建 article 和 user包, 分别用于存放 文章模块 和 用户模块的视图文件
定义视图函数
- 在 user包中创建 passport文件, 用于存放用户认证相关的视图函数
- 定义 SMSCodeResource类视图, 实现 get视图函数 用于测试
# app/resources/user/passport.py
from flask_restful import Resource
class SMSCodeResource(Resource):
"""获取短信验证码"""
def get(self):
return {'foo': 'get'}
3. 蓝图初始化
在 user包的初始化文件中进行蓝图的初始化处理
# app/resources/user/__init__.py
from flask import Blueprint
from flask_restful import Api
from .passport import SMSCodeResource
# 1.创建蓝图对象
user_bp = Blueprint('user', __name__)
# 2.创建Api对象
user_api = Api(user_bp)
# 3.添加类视图
user_api.add_resource(SMSCodeResource, '/sms/codes')
4. 注册蓝图
在 app包的初始化文件中定义函数register_bp注册蓝图
# app/__init__.py
def register_bp(app:Flask):
"""注册蓝图"""
from app.resources.user import user_bp # 进行局部导入, 避免组件没有初始化完成
app.register_blueprint(user_bp)
def create_app(type):
"""创建应用 和 组件初始化"""
...
# 注册蓝图
register_bp(app)
return app
5. 设置JSON转换函数
- 在 common/utils包中导入物料文件 output.py, 其中定义了Json转换函数
# common/utils/output.py
from flask import make_response, current_app, request
from flask_restful.utils import PY3
from json import dumps
def output_json(data, code, headers=None):
"""Makes a Flask response with a JSON encoded body"""
if 'message' not in data:
data = {
'message': 'OK',
'data': data
}
settings = current_app.config.get('RESTFUL_JSON', {})
# If we're in debug mode, and the indent is not set, we set it to a
# reasonable value here. Note that this won't override any existing value
# that was set. We also set the "sort_keys" value.
if current_app.debug:
settings.setdefault('indent', 4)
settings.setdefault('sort_keys', not PY3)
# always end the json dumps with a new line
# see https://github.com/mitsuhiko/flask/pull/1262
dumped = dumps(data, **settings) + "\n"
resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
- 在 user包的初始化文件中, 使用组件对象设置json转换函数
# app/resources/user/__init__.py
...
# 设置json包装格式
from utils.output import output_json
user_api.representation('application/json')(output_json)
# 添加类视图
user_api.add_resource(SMSCodeResource, '/sms/codes')