首页 > 技术文章 > FastAPI 工程管理(二) 工程设置

mazhiyong 2020-07-26 21:16 原文

作者:麦克煎蛋   出处:https://www.cnblogs.com/mazhiyong/ 转载请保留这段声明,谢谢!

 

在许多情况下,我们的应用都需要一些外部的配置项,比如加密密钥、数据库账号、邮件服务等等。

大部分这些设置项都是可变变量,比如数据库地址等,因此通常情况下可以通过环境变量来提供这些设置项。

一、通过环境变量使用设置

1、直接使用环境变量

我们可以在终端里直接创建和使用环境变量。

➜  ~ export MY_NAME="Mike"~ echo $MY_NAME
Mike
➜  ~ echo "Hello $MY_NAME"
Hello Mike

2、在Python中使用环境变量

我们可以在Python中直接使用环境变量。

➜  ~ python
Python 2.7.15 (default, Jul 23 2018, 21:27:06)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> name = os.getenv("MY_NAME", "World")
>>> print("Hello %s from Python" % name)
Hello Mike from Python

os.getenv()的第二个参数是缺省返回值。

我们也可以在Python文件(这里命名为main.py)中直接使用环境变量:

import os

name = os.getenv("MY_NAME", "World")
print("Hello %s from Python" % name)

然后在终端中调用Python文件:

➜  export MY_NAME="Mike"
➜  python main.py
Hello Mike from Python
➜  export MY_NAME="Beijing"
➜  python main.py          
Hello Beijing from Python

 

以上声明的变量对所有应用可见。我们也可以创建仅对特定应用可见的环境变量,并且仅存在于特定应用的运行期。

我们只需要在调用应用的时候声明变量即可。

 ➜  MY_NAME="Jack" python main.py
Hello Jack from Python
➜  python main.py
Hello World from Python

二、Pydantic设置

Pydantic提供了强有力的工具来处理来自环境变量的设置项。

1、创建Settings对象

通过从Pydantic导入BaseSettings基类,然后创建这个基类的子类(如Settings),Pydantic就会读取环境变量到这个子类的属性中。

与Pydantic模型类似,我们可以在这个子类中声明带类型注解的属性,同时也支持设置属性的默认值。

我们可以利用与Pydantic模型同样的数据校验特性和通过Field()实现的其他校验。

from pydantic import BaseSettings


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50


settings = Settings()

Pydantic读取环境变量的时候是大小写不敏感的,因此环境变量 APP_NAME 会被读写成属性 app_name

2、使用Settings对象

我们可以在应用中直接使用settings对象。

from fastapi import FastAPI

app = FastAPI() @app.get("/info") async def info(): return { "app_name": settings.app_name, "admin_email": settings.admin_email, "items_per_user": settings.items_per_user, }

我们可以在终端中运行并测试:

➜  ADMIN_EMAIL="test@qq.com" APP_NAME="settings" uvicorn settings:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [7771]
INFO:     Started server process [7779]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

页面访问结果:

3、在独立模块中保存Settings

我们可以在独立的模块文件中保存Settings,这里我们在config.py中保存。

from pydantic import BaseSettings


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50


settings = Settings()

然后我们在另一个文件中调用:

from fastapi import FastAPI

from . import config

app = FastAPI()


@app.get("/info")
async def info():
    return {
        "app_name": config.settings.app_name,
"admin_email": config.settings.admin_email,
"items_per_user": config.settings.items_per_user,
    }

4、在依赖项中使用Settings

配置文件(config.py):

from pydantic import BaseSettings


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

注意这里我们并没有创建缺省的实例对象 settings = Settings()

调用文件:

from functools import lru_cache

from fastapi import Depends, FastAPI

from . import config

app = FastAPI()


@lru_cache()
def get_settings():
    return config.Settings()


@app.get("/info")
async def info(settings: config.Settings = Depends(get_settings)):
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }

三、从.env文件中读取设置

1、.env文件

ADMIN_EMAIL="deadpool@example.com"
APP_NAME="ChimichangApp"

2、读取.env文件

Pydantic需要安装以下组件支持对.env文件的读取。

pip install python-dotenv

同时我们需要更新配置文件(config.py):

from pydantic import BaseSettings


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

    class Config:

这里的env_file指定了我们所用的文件名称。

Config类用来实现对Pydantic的配置,详细信息可以参考 Pydantic Model Config

四、通过lru_cache优化读取设置

读取文件一般都会有所耗时,但每次我们执行

config.Settings()

都会创建一个新的Settings对象,并且会重新读取硬盘文件。

但通过使用装饰器@lru_cache(),Settings对象就只会在第一次访问的时候创建一次,以后的访问会直接返回已创建的对象。

@lru_cache()
def get_settings():
    return config.Settings()

如果函数的参数不同,则会重新创建新的对象。关于@lru_cache()的更多信息,可以参考Python docs for @lru_cache()

 

推荐阅读