Flask中,之前是根据手动设置代码:
app = Flask(__name__)
CORS(app)
app.config.from_object('config.DevelopmentConfig')
# app.config.from_object('config.ProductionConfig')决定到底加载dev开发还是production生产的配置:
config.py
class BaseConfig(object): DEBUG = False FLASK_PORT = 32851 FLASK_HOST = "0.0.0.0" ... class DevelopmentConfig(BaseConfig): DEBUG = True # for local dev, need access remote mongodb MONGODB_HOST = "47.x.x.x" FILE_URL_HOST = "127.0.0.1" class ProductionConfig(BaseConfig): FILE_URL_HOST = "47.x.x.x"
但是每次发布后,都要手动改代码是
config.DevelopmentConfig
还是:
config.ProductionConfig
不够智能。
后来接触到Django中,发现是利用.env
xxx/requirements.txt
python-dotenv==0.7.1
xxx/conf/development/.env
SECRET_KEY = 'xxx' DATABASE_HOST = "localhost" DATABASE_NAME = 'xxx' MONGODB_HOST = 'localhost' MONGODB_PORT = '27017' MONGODB_USERNAME = '' MONGODB_PASSWORD = '' MONGODB_AUTH_SOURCE = ''
/xxx/conf/production/.env
也有自己的配置:
如此,在运行Django的时候,通过:
xxx/wsgi.py
中的:
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conf.production.settings")加载了production的配置。
而此处,希望:
给Flask中,也去利用,类似于python-dotenv
可以实现:
通过gunicorn的command传入env相关参数
或者是:设置换环境变量
》是dev还是prod
然后代码中,自动检测出当前环境,加载对应配置,无需手动修改代码
flask python-dotenv
抽空去试试
抽空参考上面的帖子去试试
还是:
和
解释的不错
然后才注意到:
xxx/conf/development/settings.py
"""
Django settings for xxx project.
Generated by 'django-admin startproject' using Django 2.0.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""
import os
# import datetime
from os.path import join, dirname
from dotenv import load_dotenv
dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
...就是这么使用的。
去折腾试试
➜ xxxRobotDemoServer git:(master) ✗ pipenv install python-dotenv Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead. Installing python-dotenv... Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Collecting python-dotenv Downloading https://pypi.tuna.tsinghua.edu.cn/packages/24/3d/977140bd94bfb160f98a5c02fdfbb72325130f12a325cf993182956e9d0e/python_dotenv-0.9.1-py2.py3-none-any.whl Installing collected packages: python-dotenv Successfully installed python-dotenv-0.9.1 Adding python-dotenv to Pipfile's [packages]... Pipfile.lock (f83e81) out of date, updating to (81f0dc)... Locking [dev-packages] dependencies... Locking [packages] dependencies... Updated Pipfile.lock (81f0dc)! Installing dependencies from Pipfile.lock (81f0dc)... 🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 34/34 — 00:00:09
然后继续写代码试试
写代码之前,先去搞懂:
【已解决】Python中获取环境变量中os.environ.get和os.getenv的区别
然后再去用代码:
文件结构:
➜ xxxRobotDemoServer git:(master) ✗ tree -L 3 . . ├── Pipfile ├── Pipfile.lock ├── README.md ... ├── app.py ├── conf │ ├── __init__.py │ ├── development │ │ └── __init__.py │ ├── production │ │ └── __init__.py │ └── settings.py ...
其中文件:
conf/development/.env
DEBUG = True # for local dev, need access remote mongodb MONGODB_HOST = "xxx" FILE_URL_HOST = "127.0.0.1"
conf/production/.env
DEBUG = False # for production server, need access server itself mongo, so is localhost MONGODB_HOST = "localhost" FILE_URL_HOST = "xxx"
conf/settings.py
import os
from os.path import join, dirname
from dotenv import load_dotenv
################################################################################
# Common Settings
################################################################################
DEBUG = False
FLASK_PORT = 32851
# FLASK_HOST = "127.0.0.1"
# FLASK_HOST = "localhost"
# Note:
# 1. to allow external access this server
# 2. make sure here gunicorn parameter "bind" is same with here !!!
FLASK_HOST = "0.0.0.0"
# default to production sever's local mongodb
MONGODB_HOST = "localhost"
...
# for periodical celery task
CELERY_TIMEZONE = "Asia/Shanghai"
CELERY_ENABLE_UTC = True
CELERY_REFRESH_MS_TOKEN_INTERVAL = 60 * 9 # 9 minutes (< 10 minutes)
# for debug
# CELERY_REFRESH_MS_TOKEN_INTERVAL = 30
################################################################################
# Load .env for development/production mode
################################################################################
print("Before load .env: DEBUG=%s, MONGODB_HOST=%s, FILE_URL_HOST=%s" %
(DEBUG, MONGODB_HOST, FILE_URL_HOST))
# FLASK_ENV_DEFAULT = "production"
FLASK_ENV_DEFAULT = "development"
cur_flask_environ = os.getenv("FLASK_ENV")
print("cur_flask_environ=%s" % cur_flask_environ)
cur_dir = dirname(__file__)
print("cur_dir=%s" % cur_dir)
env_folder = FLASK_ENV_DEFAULT
if cur_flask_environ:
env_folder = cur_flask_environ
print("env_folder=%s" % env_folder)
dotenv_path = os.path.join(cur_dir, env_folder, '.env')
print("dotenv_path=%s" % dotenv_path)
dotenv_load_ok = load_dotenv(dotenv_path)
print("dotenv_load_ok=%s" % dotenv_load_ok)
DEBUG = os.getenv("DEBUG")
MONGODB_HOST = os.getenv("MONGODB_HOST")
FILE_URL_HOST = os.getenv("FILE_URL_HOST")
print("After load .env: DEBUG=%s, MONGODB_HOST=%s, FILE_URL_HOST=%s" %
(DEBUG, MONGODB_HOST, FILE_URL_HOST))相关的:__init__.py 都是空白
app.py
去调用:
from conf import settings
app = Flask(__name__)
CORS(app)
print("in flask app: settings=%s" % (settings))
# app.config.from_object('config.DevelopmentConfig')
# app.config.from_object('config.ProductionConfig')
# print("for debug: after load from config.DevelopmentConfig: app.config=%s" % (app.config))
app.config.from_object(settings)
print("for debug: after load from settings: app.config=%s" % (app.config))基本上可以输出我们要的效果:

log输出是:
Before load .env: DEBUG=False, MONGODB_HOST=localhost, FILE_URL_HOST=127.0.0.1
cur_flask_environ=None
cur_dir=/Users/crifan/dev/dev_root/company/xxx/projects/robotDemo/server/xxxRobotDemoServer/conf
env_folder=development
dotenv_path=/Users/crifan/dev/dev_root/company/xxx/projects/robotDemo/server/xxxRobotDemoServer/conf/development/.env
dotenv_load_ok=True
After load .env: DEBUG=True, MONGODB_HOST=47.x.x.x, FILE_URL_HOST=127.0.0.1
curFolderPath=/Users/crifan/dev/dev_root/company/xxx/projects/NLP/sourcecode/xxx/util
projectRootPath=/Users/crifan/dev/dev_root/company/xxx/projects/NLP/sourcecode/xxx/util/..
projectRootAbsPath=/Users/crifan/dev/dev_root/company/xxx/projects/NLP/sourcecode/xxx
mainConfFileFullPath=/Users/crifan/dev/dev_root/company/xxx/projects/NLP/sourcecode/xxx/conf/main.conf
configParser=<configparser.ConfigParser object at 0x112500fd0>
mysqlConfigDict={'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'password': 'crifan_mysql', 'db': 'xxx', 'charset': 'utf8'}
in flask app: settings=<module 'conf.settings' from '/Users/crifan/dev/dev_root/company/xxx/projects/robotDemo/server/xxxRobotDemoServer/conf/settings.py'>
for debug: after load from settings: app.config=<Config {'ENV': 'production', 'DEBUG': 'True', 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'AUDIO_TEMP_FOLDER': 'tmp/audio', 'CELERY_BROKER_URL': '
redis://localhost:6379/0
', 'CELERY_DELETE_TMP_AUDIO_FILE_DELAY': 120, 'CELERY_ENABLE_UTC': True, 'CELERY_REFRESH_MS_TOKEN_INTERVAL': 540, 'CELERY_TIMEZONE': 'Asia/Shanghai', 'FILE_URL_HOST': '127.0.0.1', 'FLASK_APP_NAME': 'RobotQA', 'FLASK_ENV_DEFAULT': 'development', 'FLASK_HOST': '0.0.0.0', 'FLASK_PORT': 32851, 'LOG_FILE_BACKUP_COUNT': 10, 'LOG_FILE_FILENAME': 'logs/RobotQA.log', 'LOG_FILE_MAX_BYTES': 2097152, 'LOG_FORMAT': '[%(asctime)s %(levelname)s %(filename)s:%(lineno)d %(funcName)s] %(message)s', 'MONGODB_AUTH_SOURCE': 'gridfs', 'MONGODB_HOST': '47.x.x.x', 'MONGODB_PASSWORD': 'ppwwdd', 'MONGODB_PORT': 23026, 'MONGODB_USERNAME': 'gridfs', 'MS_GET_TOKEN_URL': '
https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken
', 'MS_STT_URL': '
https://westus.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US
', 'MS_TTS_SECRET_KEY': 'dxxxf', 'MS_TTS_URL': '
https://westus.tts.speech.microsoft.com/cognitiveservices/v1
'}>加载配置后,关于如何引用,使用这些环境变量,和之前类似可以用app.config[“xxx”]或settings.xxx
print("for debug: output some config value:")
print("settings.DEBUG=%s, settings.MONGODB_HOST=%s, settings.FILE_URL_HOST=%s" %
(settings.DEBUG, settings.MONGODB_HOST, settings.FILE_URL_HOST))
print('app.config["DEBUG"]=%s, app.config["MONGODB_HOST"]=%s, app.config["FILE_URL_HOST"]=%s' %
(app.config["DEBUG"], app.config["MONGODB_HOST"], app.config["FILE_URL_HOST"]))输出:
for debug: output some config value: settings.DEBUG=True, settings.MONGODB_HOST=xxx, settings.FILE_URL_HOST=127.0.0.1 app.config["DEBUG"]=True, app.config["MONGODB_HOST"]=xxx, app.config["FILE_URL_HOST"]=127.0.0.1
另外,也想起来了:
对于从settings中获取配置的话,有个好处:
支持额外设置字典类型参数,比如:
conf/app/settings.py
DEMO_USER = {
"name": "crifan",
"password": "crifan_pwd"
}然后调用:
app.config.from_object(settings)
print('settings.DEMO_USER=%s, settings.DEMO_USER["name"]=' % settings.DEMO_USER, settings.DEMO_USER["name"])输出:
settings.DEMO_USER={'name': 'crifan', 'password': 'crifan_pwd'}, settings.DEMO_USER["name"]= crifan【已解决】Flask中从.env中加载ini类型的配置得到的变量类型不是原始类型而都是字符串
然后接着再去尝试:
在PyCharm中调试时,在命令行中传入FLASK_ENV对应的值,分别是development和production,看看能否正常记载对应的.env的配置:
Run-Edit Configurations ->Environment->Environment variables ->点击… 新增
FLASK_ENV=development




然后再去调试,看看代码中:
cur_flask_environ = os.getenv("FLASK_ENV")能否获取对应的值:
可以的:

然后再改为:
FLASK_ENV=production

试试,也是可以的:

顺带,再去优化配置文件结构,去改为:
➜ xxxRobotDemoServer git:(master) ✗ tree . ... ├── app.py ├── conf │ ├── __init__.py │ ├── app │ │ ├── __init__.py │ │ ├── development │ │ │ └── __init__.py │ │ ├── production │ │ │ └── __init__.py │ │ └── settings.py │ ├── gunicorn │ │ └── gunicorn_config.py │ └── supervisor │ ├── supervisord_local.conf │ └── supervisord_server.conf ...

导入方式也变成:
# from conf import settings from conf.app import settings
然后接着要去:
【已解决】Flask本地和线上用gunicorn和supervisor部署时如何传入环境变量
【总结】