其实本质都是python-dotenv加载环境变量出现的问题。
坑一:python-dotenv加载的Value都是字符串类型
第一个坑是python-dotenv加载的Value都是字符串类型(python-dotenv
版本0.10.1),因此导致整型、浮点型和布尔类型需要转换一下。
解决方案
目前解决办法只能是这样:
# `.env`
MAIL_PORT = 465
MAIL_USE_SSL = false
MAIL_USE_TLS = true
# settings.py
class BaseConfig(object):
...
MAIL_PORT = int(os.getenv('MAIL_PORT', default=587))
MAIL_USE_SSL = True if 'true' == os.getenv('MAIL_USE_SSL') else False
MAIL_USE_TLS = True if 'true' == os.getenv('MAIL_USE_TLS') else False
相关帖子:
坑二:pipenv影响了flask加载.env
环境变量
第二个坑和pipenv
有关,众所周知Flask项目可以通过.env
加载环境变量,但是,pipenv
也可以通过.env
加载环境变量!问题就出现了,进入pipenv shell
虚拟环境后,修改.env环境变量后再启动Flask app:flask run
,Flask还是用了原来的环境变量!!!
究其原因,是pipenv shell
加载了环境变量并进行了缓存,然后flask加载环境变量时没有进行覆盖
> pipenv shell
Loading .env environment variables…
Launching subshell in virtual environment…
...
> flask run # 正常预期
# 停止flask,修改 .env 环境变量,保存
> flask run # 没达到修改变量后的预期效果
尤其是部署Flask到服务器后,以下步骤肯定有问题的!!!
$ pipenv shell $ vim .env ... $ flask run
解决方案
方案一:重进pipenv shell
一种解决方案就是退出pipenv shell
环境再进入:
> pipenv shell
> # 编辑 .env
...
> exit
> pipenv shell
方案二:新建并使用app.py
启动
另一个解决方案是在主目录下新建一个app.py
,拷贝下面代码,以后使用python app.py
启动。
# coding=utf-8
"""
python app.py
"""
import os
from dotenv import load_dotenv
dotenv_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path, override=True) # override=True: 覆写已存在的变量
from apps.web import create_app
app = create_app()
if __name__ == "__main__":
app.run()
这种代码有时也会给一些wsgi(比如gunicorn)提供。
方案三:设置PIPENV_DONT_LOAD_ENV=1
还有一个方案是设置PIPENV_DONT_LOAD_ENV=1
,不让pipenv加载.env
。
PowerShell示例(注意没有了Loading .env environment variables…
信息):
> $env:PIPENV_DONT_LOAD_ENV=1
> pipenv shell
Launching subshell in virtual environment…
Windows PowerShell
...
方案四:使用.flaskenv
pipenv shell
不会从.flaskenv
加载变量,所以如果有经常需要修改的环境变量也可以放在.flaskenv
。但是我感觉一点也不优雅,因为我习惯把.flaskenv
也提交到仓库,而留下.env
在部署端客制化。
另外,对于这个坑我还找到一个彩蛋,李辉老师已经在17年提过类似的Issue了哈哈。
其实我认为flask加载时,覆写python-dotenv环境变量比较好。