上一篇介绍了总体的设计和技术选型,这一篇将开始构建项目。
工厂函数
首先来构造工厂函数,编写app/__init__.py
:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yujichang
import os
import logging
import click
from flask import Flask, make_response
from flask_cors import CORS
from config import config
from app.extensions import db, migrate
from logging.handlers import RotatingFileHandler
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def create_app(config_name=None):
if config_name is None:
config_name = os.getenv('FLASK_CONFIG', 'development')
""" 使用工厂函数初始化程序实例"""
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(config[config_name])
CORS(app, supports_credentials=True)
db.init_app(app)
migrate.init_app(app, db)
register_logging(app)
register_request_handlers(app)
register_blueprints(app)
register_shell_context(app)
register_commands(app)
return app
def register_logging(app):
"""
配置日志信息
"""
# ensure the logs folder exists
try:
os.makedirs(os.path.join(basedir, 'logs'))
except OSError:
pass
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler = RotatingFileHandler(os.path.join(os.path.join(basedir, 'logs'), 'results.log'),
maxBytes=10 * 1024 * 1024, backupCount=10)
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.INFO)
if not app.debug:
app.logger.addHandler(file_handler)
def register_request_handlers(app):
@app.after_request
def allow_cors(response):
response = make_response(response)
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE'
response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type,authorization'
return response
def register_blueprints(app):
# 注册蓝本 api
from .api import api as api_blueprint
app.register_blueprint(api_blueprint, url_prefix='/api')
# 注册蓝本 main
from .main import main as main_blueprint
app.register_blueprint(main_blueprint, url_prefix='/user')
def register_commands(app):
@app.cli.command()
@click.option('--drop', is_flag=True, help='Create after drop.')
def initdb(drop):
"""Initialize the database."""
if drop:
click.confirm('This operation will delete the database, do you want to continue?', abort=True)
db.drop_all()
click.echo('Drop tables.')
db.create_all()
click.echo('Initialized database.')
def register_shell_context(app):
@app.shell_context_processor
def make_shell_context():
from app.models import Class, Student, Result, Statistics, class_student, User
return dict(db=db, Class=Class, Student=Student, Result=Result, Statistics=Statistics, User=User,
class_student=class_student)
在工厂函数中添加了以下功能:
- 使用了flask_cors来处理跨域问题。
- 注册扩展模块SQLAlchemy、Migrate。
- 添加了日志logger。
- 注册蓝图main和api。
- 注册cli command,通过comand初始化数据库。
- 注册flask shell上下文,引入数据库模型。
配置文件
工厂函数调用配置文件,配置全局配置,编写config.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yujichang
import os
import hashlib
basedir = os.path.abspath(os.path.dirname(__file__))
class BaseConfig(object):
SECRET_KEY = os.getenv('SECRET_KEY') or hashlib.new(name='md5', data=b'you secret_key').hexdigest()
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_RECORD_QUERIES = True
SQLALCHEMY_ECHO = False
ALLOWED_FILE_EXTENSIONS = ['xls', 'xlsx', 'csv', 'txt']
FILE_UPLOAD_PATH = os.path.join(basedir, 'uploads')
class DevelopmentConfig(BaseConfig):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(os.path.join(basedir, 'instance'), 'data-dev.db')
class TestingConfig(BaseConfig):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' # in-memory database
class ProductionConfig(BaseConfig):
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
'sqlite:///' + os.path.join(os.path.join(basedir, 'instance'), 'data.db'))
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig
}
主要配置了sqlite数据库的连接路径和相关参数,上传文件允许的后缀。
扩展文件
扩展文件主要是引入SQLAlchemy、Migrate,实现数据库的管理,编写app/exsentions.py
:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yujichang
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy()
migrate = Migrate()
构建蓝图
构建api蓝图,编写app/api/__init__.py
:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yujichang
from flask import Blueprint
api = Blueprint('api', __name__)
from . import errors, classes, students, results, statistics, auth
文件最后引入了classes、students、results、statistics等模块,将班级管理、学生管理、成绩管理、统计分析的路由添加到api蓝图里。
构建main蓝图,编写app/main/__init__.py
:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yujichang
from flask import Blueprint
main = Blueprint('main', __name__, template_folder="templates", static_url_path='', static_folder='static')
from . import view, errors
main蓝图是主路由,包含登陆和注册两个路由。
构建完配置文件、扩展文件、工厂函数、蓝图后,基本框架已构建完成,下一篇将整理数据库模型,初始化数据库。