Flask:文件配置方式实践及其中的各种问题记录
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,
提示:
1.请查看本文后面的“18-07-17 11:18重大纠正” !
2.flask run命令运行时传入参数给create_app的方法也有了,参考后面的18-07-18 12:47更新!
3.请查看18-07-18 13:16更新:instance_relative_config=True,很重要!原来孤创建Flask应用时使用了这个参数,所以参会有一些列instance目录的问题!
----正文----
昨日创建了一个Flask应用,一直都是使用flask run命令来执行,期间在Flask配置部分遇到了问题,然后,遇见了下面的好文:
原来,Flask项目下可以有个config.py文件或者config包——其中包含各种环境(本地、生产、其它)的默认配置文件,然后使用app.config.from_object()函数从这些默认配置中获取配置来启动Flask应用——需要条件判断,这个条件判断的值来自create_app或make_app工厂函数的参数。
在当前的Flask中,create_app或make_app的参数默认类型为ScriptInfo,不是很了解;不过,也可以传入字典或其它,可以不只一个参数,由开发者根据需要自行决定。
除了默认的config.py文件或者config包外,开发者还可以在instance目录(自己还不是特别熟悉)下放置敏感级别高的配置文件,比如,数据库密码。
在使用flask run命令运行应用时,instance目录位于项目的根目录下,可以使用app.config.from_pyfile('config.py')函数来获取配置启动Flask应用,这也是官文Application Factories中使用def create_app(config_filename)、app.config.from_pyfile(config_filename)的原因。前面一直用flask run命令运行,所以,使用print获取的信息显示config_filename为ScriptInfo类型,但没有配置文件——之前自己没有建立instance目录。
现在,进入新阶段吧!使用程序调用create_app(...)函数来创建Flask应用并运行!在上面的参考好文中以及其它一些资料中,都是这么运行Flask应用的,恐怕全世界只有自己没有这么玩过了!不过,现在这个状况已经成为过去了!
下面是自己的create_app的代码(最终版本):
# started from 2018-07-16
from flask import Flask def create_app(config = None):
app = Flask(__name__, instance_relative_config=True) # 根据传入的config决定使用哪个默认配置
# 在flask run时执行错误!此时config的类型为ScriptInfo,是不存在get()函数的
# 目前传入为字典类型,后面可以更改为ScriptInfo类型,官文说它未来有很大用处
# config还可以为None
app_config = 'default' if isinstance(config, dict):
app_config = config.get('config') if app_config not in ['default', 'deploy']:
print('错误:不存在的配置:', app_config)
print('提示:重置为默认配置启动')
app_config = 'default' app.config.from_object('config.' + app_config) # 来自instance目录的配置文件
app.config.from_pyfile('config.py') from . import mdb, news mdb.init_app(app) app.register_blueprint(news.bpnews) return app
建立程序使用create_app(...)创建Flask应用的代码(runApp.py):
# runApp.py for webnews project
from webnews import create_app # config: default or deploy
app = create_app({'config':'defaul1t'})
app.run()
说明,runSpider.py位于项目webnews的根目录——因为项目尚未安装、整个项目在virtualenv中运行。
在runApp.py中,导入了create_app,并使用它创建Flask应用,传入参数为一个简单的字典;
因为这里传入的是字典,所以,在create_app()函数运行后接收到的也是字典(而不是默认的ScriptInfo,当然,也可以在程序中创建ScriptInfo对象来传入配置数据,或许和instance的位置有关系),函数中的操作也主要是对字典类型的config的类型判断和数据读取。
在上面的程序定义下,create_app只可以传入一个参数,可以是字典,也可以为None,也可以为其它任何类型,但是,程序中只对字典类型进行了判断并处理,如果不是字典,那么,忽略,并使用默认配置启动。
上面的程序既可以使用flask run命令来启动,也可以使用类似runApp.py的程序来启动——这也是为什么之前说这种工程函数方式可以启动多个Flask应用的原因所在。
注意,使用上面的runApp.py运行Flask应用时,instance目录不再是项目下的instance目录了。因为程序运行中virtualenv中,此时,instance目录为虚拟环境根目录下的var\\webnews-instance——或许可以配置为其它的,var有点像Linux下的目录名,后面会看到这个错误提示的截图。
下面展示一些完善过程中的调试过程:
-最开始运行,没有找到instance目录
-按照错误提示建立instance目录
-instance目录建立后,运行成功
-DEBUG = True:开启调试模式
-以为config是ScriptInfo类型,所以调用config.data来获取数据,结果失败了!
-获取传入的配置字典参数
-获取成功,并使用默认配置运行(项目的config目录下default.py文件,还有一个deploy目录)
-传入错误的配置参数,运行失败
-修改代码后——添加判断和提示,运行成功
-flash run运行失败:这种方式运行时没有传入配置参数(怎么传入呢?),此时config为None
-完善后的程序(近期的最终版本,不考虑传入参数为ScriptInfo类型)
发现一个问题:即便我的默认配置设置了DEBUG为True,但是,在flask run命令运行时却无法开启——设置环境变量FLASK_ENV为development当然是可以的了。
18-07-17 11:18重大纠正:
弄错了!
前面使用传入的参数config来使用项目根目录下config里面的配置文件,其实,应该做的是根据config来决定使用instance目录中的配置文件。
看来孤的代码要修改了啊!
18-07-17 12:29代码更新:
# runApp.py
from webnews import create_app # 参数为instance目录下的配置文件名
# 目前可选:dev.py,prod.py,后续可以自行添加
# dev.py、prod.py位于instance目录中,可以使用app.config.root_path查看具体在哪里。
app = create_app({'config_fn':'dev.py'}) app.run() # create_app(...)
from flask import Flask def create_app(config_fn = None):
app = Flask(__name__, instance_relative_config=True) # 从config包下的default.py文件获取配置信息
app.config.from_object('config.default') # print('app.config.root_path:', app.config.root_path) # debug #
# 根据传入的config决定使用哪个配置:来自instance目录(app.config.root_path)
# 在flask run时执行错误!此时config的类型为ScriptInfo,是不存在get()函数的
# 目前传入为字典类型,后面可以更改为ScriptInfo类型,官文说它未来有很大用处
# config还可以为None
if isinstance(config_fn, dict):
# 获取配置中的参数
instance_config = config_fn.get('config_fn') # 获取成功!
# 但不确定是否为文件名、文件是否有效,将使用app.config.from_pyfile(instance_config)配置应用
# 需要做异常判断
#
# 非None、str类型判断(是否可以为bytes?)
if instance_config and isinstance(instance_config, str):
try:
app.config.from_pyfile(instance_config)
except FileNotFoundError as e:
print('错误:参数config_fn:', config_fn)
print('错误:配置文件未找到!')
print(e)
except Exception as e:
# 输出错误信息
print('错误参数config_fn:', config_fn)
print('错误:其它错误!')
print(e)
else:
# 配置成功,输出提示消息
print('消息:使用%s配置app!' % instance_config)
else:
# flask run命令执行时config_fn一般为None,不做处理
# flask run命令执行时,怎么判断并使用项目的instance目录下的配置文件呢?
print('警告:参数config_fn的类型(%s)并非字典!' % type(config_fn))
print('警告:将使用默认配置文件dev.py进行配置!')
# 使用项目根目录下的配置文件dev.py进行配置
# 需要确保此文件存在,否则,数据库访问会不成功,
# 找到动态配置的方法再改进
# 程序中执行时也会传送空参数
try:
app.config.from_pyfile('dev.py')
except Exception as e:
print('错误:默认配置dev.py不存在,无法使用其完成配置!')
else:
print('警告:使用默认dev.py配置成功!') # 现在,亟需知道flask run传入参数的方式!
# 环境变量?WEBNEWS_CONF_FILE?
# app.config.from_envvar(‘APP_CONFIG_FILE’)将加载由环境变量APP_CONFIG_FILE指定的文件。
# 这个环境变量的值应该是一个配置文件的绝对路径。
# TBD # 应用扩展、蓝图配置等
from . import mdb, news mdb.init_app(app) app.register_blueprint(news.bpnews) return app
webnews创建应用代码
18-07-18 12:47更新:
终于找到flask run命令运行时如何给create_app传递参数的方法了——官文Command Line Interface。
测试:set FLASK_APP=webnews:create_app({"config_fn":"dev.py"}),成功!就是太长了点!这也难怪官文传递的参数为config_filename!懂了!
18-07-18 13:16更新:instance_relative_config=True
请注意我上面代码中创建app的参数instance_relative_config=True,这表明使用instance目录,如果设置为False,则不适用,会影响创建的app的app.config.root_path的值。
在上面的代码中,若是设置为False,则app.config.root_path一律为项目下的目录:此时程序运行和flask run运行的结果相同,默认为False。显然,这样的默认值是不试用的。
再次更新后的代码:
from flask import Flask def create_app(config_fn = None):
'''
创建Flask应用,并使用用户提供的instance目录下的配置文件配置应用
参数config_fn格式:{'config_fn':'filename.py'}
注意:请确定配置文件存在,否则,将不会发生配置
注意:请确定运行时的instance目录是否存在
'''
# 注意:instance_relative_config这个参数很重要!关系到是否使用instance目录!
app = Flask(__name__, instance_relative_config=True) print('app.config.root_path = ', app.config.root_path) # debug # 从config包下的default.py文件获取配置信息
app.config.from_object('config.default') # 根据传入的config决定使用哪个配置:来自instance目录(app.config.root_path)
# 目前使用字典方式传入配置文件名:
# {'config_fn':'dev.py'}
if isinstance(config_fn, dict):
# 获取配置中的参数
instance_config = config_fn.get('config_fn') # 获取成功!
# 但不确定是否为文件名、文件是否有效,将使用app.config.from_pyfile(instance_config)配置应用
# 需要做异常判断
#
# 非None、str类型判断(是否可以为bytes?)
if instance_config and isinstance(instance_config, str):
try:
# 使用配置文件配置应用
app.config.from_pyfile(instance_config)
except FileNotFoundError as e:
print('错误:参数config_fn:', config_fn)
print('错误:配置文件未找到!')
print(e)
except Exception as e:
# 输出错误信息
print('错误参数config_fn:', config_fn)
print('错误:其它错误!')
print(e)
else:
# 配置成功,输出提示消息
print('消息:使用%s配置app!' % instance_config)
else:
# 参数不符合本函数定义的规则
print('警告:参数config_fn的类型(%s)并非字典!' % type(config_fn)) # 应用扩展、蓝图配置等
from . import mdb, news mdb.init_app(app) app.register_blueprint(news.bpnews) return app
create_app
后记
感觉学习Flask走上正轨了!
可以编写run程序了,接下来就是部署了:
-使用Apache+mod_wsgi运行Flask应用
-使用Nginx+uWSGI运行Flask应用
-使用Tornado运行Flask应用
-使用Gunicorn运行Flask应用
好多啊!来自Flask进阶系列(八)–部署和分发 by Billy.J.Hee的技术博客,昨晚发现,超级好的!
当然,不懂得、不清楚的还不少,都需要练习啊!
之前五月看过一遍Flask的官文了,以为自己OK呢,结果,才做这么个小小的项目就遇到这么多问题!真是……
做项目!做项目!做项目!
真的很重要的!也是学习东西最好的方式!
今天的任务列表中,最最重要的就是继续昨天的项目了!
加油!
Flask官文配置参考链接:
Flask:文件配置方式实践及其中的各种问题记录的更多相关文章
- Spring Cloud Config 配置中心实践过程中,你需要了解这些细节!
本文导读: Spring Cloud Config 基本概念 Spring Cloud Config 客户端加载流程 Spring Cloud Config 基于消息总线配置 Spring Cloud ...
- 【Oracle/Java】以Insert ALL方式向表中插入百万条记录,耗时9分17秒
由于按一千条一插程序长期无反应,之后改为百条一插方式,运行完发现插入百万记录需要9m17s,虽然比MySQL效率差,但比单条插入已经好不少了. 对Oracle的批量插入语法不明的请参考:https:/ ...
- spring,springmvc,mybatis基本整合(一)--xml文件配置方式(1)
**这个整合.仅仅是最主要的整合,而且是xml配置文件的方式之中的一个,即当中的mybatis是採用非mapper接口的方式.(第二遍採用mapper接口方式.第三遍採用注解的方式:第四篇採用注解基于 ...
- Spring的xml文件配置方式实现AOP
配置文件与注解方式的有很大不同,多了很多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"?> ...
- Spring(十二)使用Spring的xml文件配置方式实现AOP
配置文件与注解方式的有非常大不同,多了非常多配置项. beans2.xml <?xml version="1.0" encoding="UTF-8"? & ...
- XML(php中获取xml文件的方式/ajax获取xml格式的响应数据的方式)
1.XML 格式规范: ① 必须有一个根元素 ② 不可有空格.不可以数字或.开头.大小写敏感 ③ 不可交叉嵌套 ④ 属性双引号(浏览器自动修正成双引号了) ⑤ 特殊符号要使用实体 ⑥ 注释和HTML一 ...
- (一)spring aop的两种配置方式。
sring aop的方式有两种:(1)xml文件配置方式(2)注解的方式实现,我们可以先通过一个demo认识spring aop的实现,然后再对其进行详细的解释. 一.基于注解的springAop配置 ...
- Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基础文件配置,Web框架的本质,服务器程序和应用程序(wsgiref服务端模块,jinja2模板渲染模块)的使用
Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基 ...
- 关于Log4Net的使用及配置方式
目录 0.简介 1.安装程序包 2.配置文件示例 3.日记的级别:Level 4.日志的输出源:Appenders 5.日志格式:Layout 6.日志文件变换方式(回滚方式):RollingStyl ...
随机推荐
- 【Cf #292 D】Drazil and Morning Exercise(树的直径,树上差分)
有一个经典的问题存在于这个子问题里,就是求出每个点到其他点的最远距离. 这个问题和树的直径有很大的关系,因为事实上距离每个点最远的点一定是直径的两个端点.所以我们可以很容易地进行$3$遍$Dfs$就可 ...
- Python 使用CPickle和pickle模块进行序列化和反序列化
#Cpickle使用C语言进行编写的相比pickle来说效率高很多 #-*-coding:utf-8-*-'''序列化操作'''try: import cPickle as pickleexce ...
- Android Studio添加文件注释头模板?
Self Settings: as中class文件头注释: File -> Settings -> Editor -> File and Code Templates -> 右 ...
- Android Studio怎么文件添加到收藏和打开收藏夹
http://jingyan.baidu.com/article/1709ad809e608b4634c4f0b9.html 在使用Android studio编写的代码的过程中,有时会碰到有一些文件 ...
- js字符串替换(时间转换)
转: js中字符串全部替换 废话不多说,直接发结果 在js中字符串全部替换可以用以下方法: str.replace(/需要替换的字符串/g,"新字符串") 比如: "yy ...
- zuul学习
1.zuul可以代理界面所需的后端服务,可以解决CORS(Cross-Origion-Resource-Sharing)和认证问题(authentication)问题 2.zuul是使用ribbon来 ...
- Mongo副本集搭建
解压mongodb-linux-x86_64-rhel70-3.2.0.tgz 将解压后的bin路径添加到系统环境变量,保证mongo.mongod等命令可用 创建副本集目录mongo/27017.2 ...
- random函数详解
1. 随机函数 Math.random() Math.random(); 取值范围是 [ 0.0,1.0 ) 的左闭右开区间.具体源代码如下所示: Math.random()是生成0~ ...
- RabbitMQ基础篇
介绍 RabbitMQ 是一个消息中间件:它接收并转发消息.您可以把它想象为一个邮局:当您把需要寄出的邮件投递到邮箱,邮差最终会把邮件送给您的收件人.在这个比喻中,RabbitMQ 就是一个邮箱,也可 ...
- 一个highcharts混合图Demo
公司要我做一个highcharts的mockup,其实半个小时就能做完了,我做了将近两个小时,唉!不过还好,总算把东西学会了.勤能补拙! 把代码贴上来 布局很简单,一个div里套两个div,给好id, ...