每个flask程序都需要创建一个app,这是flask程序运行的核心程序,在此我将app的初始化放入了模块初始化文件当中__init__.py
,代码如下
import os
import logging
import click
from logging.handlers import RotatingFileHandler
from flask import Flask, render_template, request
from flask_sqlalchemy import get_debug_queries
from flask_wtf.csrf import CSRFError
from app.util import pretty_date
from app.extensions import db, sitemap, login_manager, migrate,app_helper
from app.settings import config
from app.template_filter import register_template_filter
from app.models import AccessLog
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__)
app.config['CONFIG_NAME'] = config_name
app.config.from_object(config[config_name])
register_logging(app)
register_extensions(app)
register_blueprints(app)
register_commands(app)
register_errors(app)
register_shell_context(app)
register_request_handlers(app)
register_jiaja2_filters(app)
register_template_filter(app)
return app
def register_logging(app):
class RequestFormatter(logging.Formatter):
def format(self, record):
record.url = request.url
record.remote_addr = request.remote_addr
return super(RequestFormatter, self).format(record)
request_formatter = RequestFormatter(
'[%(asctime)s] %(remote_addr)s requested %(url)s\n'
'%(levelname)s in %(module)s: %(message)s'
)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler = RotatingFileHandler(os.path.join(basedir, 'logs/h3blog.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_extensions(app):
db.init_app(app)
login_manager.init_app(app)
sitemap.init_app(app)
migrate.init_app(app,db=db)
app_helper.init_app(app)
def register_blueprints(app):
# 注册蓝本 main
from app.main import main as main_blueprint
app.register_blueprint(main_blueprint)
# 注册蓝本 admin
from app.admin import admin as admin_blueprint
app.register_blueprint(admin_blueprint, url_prefix='/admin')
def register_shell_context(app):
@app.shell_context_processor
def make_shell_context():
from app.models import User, Article, Category, \
Tag, article_tag, Recommend, Picture
return dict(db=db, User=User, Article=Article, \
Category=Category, Tag=Tag, Recommend = Recommend, \
AccessLog = AccessLog, Picture = Picture)
def register_errors(app):
pass
def register_request_handlers(app):
from flask_login import current_user
@app.context_processor
def context_processor():
'''
上下文处理器, 返回的字典可以在全部模板中使用
'''
return {'current_user': current_user}
@app.before_request
def before_app_request():
user_agent = request.headers.get("User-Agent")
if user_agent is None:
return
remark = None
if 'Baiduspider' in user_agent :
remark = '百度'
if 'Bytespider' in user_agent :
remark = '头条搜索'
if 'YisouSpider' in user_agent:
remark = '神马搜索'
if 'Sogou' in user_agent:
remark = '搜狗'
if 'Sosospider' in user_agent:
remark = '搜搜'
if remark :
accessLog = AccessLog(ip = request.remote_addr,
url = request.path,
remark = remark)
db.session.add(accessLog)
@app.after_request
def query_profiler(response):
for q in get_debug_queries():
if q.duration >= app.config['H3BLOG_SLOW_QUERY_THRESHOLD']:
app.logger.warning(
'Slow query: Duration: %fs\n Context: %s\nQuery: %s\n '
% (q.duration, q.context, q.statement)
)
return response
def register_jiaja2_filters(app):
env = app.jinja_env
env.filters['pretty_date'] = pretty_date #注册自定义过滤器
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.')
上述代码初始化分了如下几个模块,进行初始化:
- app 根据配置文件初始化
- 配置日志模式
- 配置扩展
- 配置蓝图
- 配置命令行
- 配置错误信息
- 配置钩子函数
- 配置模板过滤器
我将各个配置过程单独成函数,方便管理与单独扩展